1

I try to write a macro like following: taken from link and I apply same rule to my software whit out success. I notice some difference from C and C++, but I don't understand why, the macro are preprocessor job ! also I notice some difference passing to the macro the values coming from an enumerators.

#include <stdio.h>
#define CONCAT(string) "start"string"end"
int main(void) 
{
    printf(CONCAT("-hello-"));
    return 0;
}

the reported link used to try online the code link to a demo on ideone allow selection of different language C is ok but changing to C++ it doesn't work. Also in my IDE Visual Studio Code (MinGw C++) doesn't work.

My final target is write a macro to parametrize printf() function, for Virtual Console application using some escape codes. I try to add # to the macro concatenation and seems work but in case I pass an enumerator to the macro I have unexpected result. the code is :

#include <stdio.h>
#define def_BLACK_TXT 30
#define def_Light_green_bck 102

#define CSI "\e["
#define concat_csi(a, b) CSI #a ";" #b "m"
#define setTextAndBackgColor(tc, bc) printf(concat_csi(bc, tc))

enum VtColors { RESET_COLOR = 0, BLACK_TXT = 30, Light_green_bck = 102 };

int main(void){
    setTextAndBackgColor(30, 102);
    printf("\r\n");
    setTextAndBackgColor(def_BLACK_TXT , def_Light_green_bck );
    printf("\r\n");
    setTextAndBackgColor(VtColors::BLACK_TXT , VtColors::Light_green_bck );
    printf("\r\n");
    printf("\e[102;30m");//  <<---   this is the expected result of macro expansion
}

//and the output is : ( in the line 3 seems preprocessor don't resolve enum (the others line are ok) )
[102;30m 
[102;30m 
[VtColors::Light_green_bck;VtColors::BLACK_TXTm
[102;30m

Obviously I want use enumerators as parameter... (or I will change to #define).

But I'm curious to understand why it happens, and why there is difference in preprocessor changing from C to C++.

If anyone know the solution, many thanks.

Diego
  • 17
  • 3
  • 2
    Of course the preprocessor doesn't resolve enums to their values. It doesn't know nor care anything about enums. – tkausl Jan 09 '23 at 00:04
  • run the preprocessor alone so you can see what being output - gcc -E for example – pm100 Jan 09 '23 at 00:06
  • so can become a STRINGIFY macro passing an enumerator. Good to know. – Diego Jan 09 '23 at 00:11
  • 2
    *"I notice some difference from C and C++,"* -- care to share those differences with the rest of the class? ("Doesn't work" doesn't cut it, especially when you neglected to say what the intended functionality is.) – JaMiT Jan 09 '23 at 06:37

2 Answers2

1

There appears to be some compiler disagreement here.

MSVC compiles it as C++ without any issues.

gcc produces a compilation error.

The compilation error references a C++ feature called "user-defined literals", where the syntax "something"suffix gets parsed as a user-defined literal (presuming that this user-defined literal gets properly declared).

Since the preprocessor phase should be happening before the compilation phase, I conclude that the compilation error is a compiler bug.

Note that adding some whitespace produces the same result whether it gets compiled as C or C++ (and makes gcc happy):

#define CONCAT(string) "start" string "end"

EDIT: as of C++11, user-defined literals are considered to be distinct tokens:

Phase 3

  1. The source file is decomposed into comments, sequences of whitespace characters (space, horizontal tab, new-line, vertical tab, and form-feed), and preprocessing tokens, which are the following:

a) header names such as or "myfile.h"

b) identifiers

c) preprocessing numbers d) character and string literals , including user-defined (since C++11)

emphasis mine.

This occurs before phase 4: preprocessor execution, so a compilation error here is the correct result. "start"string, with no intervening whitespace, gets parsed as a user-defined literal, before the preprocessor phase.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • Note mingw c++ was happy after I add concatenation # to the macro #define concat_csi(a, b) CSI #a ";" #b "m" – Diego Jan 09 '23 at 00:20
  • 1
    MSVC errors too if you enable the conforming preprocessor (`/Zc:preprocessor`). Going from memory, UDLs are a separate pptoken, so the preprocessor should recognize the syntax and not concatenate string literals here. – chris Jan 09 '23 at 00:53
  • basically what is happening here is that the C++ preprocesor is recognizing `"start"string` as a SINGLE TOKEN, as required by the C++ standard (a string with type suffix), and so not recognizing `string` as the argument to the macro (as its embedded in a string), again correct according to the standard. C does not have strings with type suffixes (as it does not have the user-defined string literal operators needed to use them), so the C preprocessor does not recognize it as a single token. – Chris Dodd Jan 09 '23 at 01:00
  • Some further digging supports @chris 's claim, I updated my answer. – Sam Varshavchik Jan 09 '23 at 01:05
  • On https://www.onlinegdb.com/online_c++_compiler the error message refers to `operator ""` (as introduced in [C++11](https://en.cppreference.com/w/cpp/language/operators)). Hence, this error happens after preprocessing and inserting the spaces in the macro definition solves it. The funny thing is that entering `"start""-hello-""end"` (without using the macro) does not give an error. – nielsen Jan 09 '23 at 09:16
-1

to summarize the behavioral is the following: (see comment in the code)

#include <stdio.h>
#define CONCAT_1(string) "start"#string"end"
#define CONCAT_2(string) "start"string"end"
#define CONCAT_3(string) "start" string "end"
int main(void) 
{
    printf(CONCAT_1("-hello-"));      // wrong insert double quote
    printf("\r\n");
    printf(CONCAT_1(-hello-));        // OK but is without quote
    printf("\r\n");
#if false
    printf(CONCAT_2("-hello-"));   // compiler error
    printf("\r\n");
#endif
    printf(CONCAT_3("-hello-"));     // OK
    printf("\r\n");
    printf("start" "-hello-" "end");    // OK
    printf("\r\n");
    printf("start""-hello-""end");      // OK
    printf("\r\n");
    return 0;
}
output:
start"-hello-"end   <<<--- wrong insert double quote
start-hello-end
start-hello-end
start-hello-end
start-hello-end
Diego
  • 17
  • 3
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 09 '23 at 13:18