Ferenc Deak
Ferenc Deak

Reputation: 35408

C/C++ macro error with quotes and backslashes

I am trying to spice up my testing framework for a scripting language with some nice C macros to not to have to write the same code more than once ... So, I have the code:

TEST_CASE("Variables", "[vm_variables]")
{
nap_runtime* runtime = nap_runtime_create(0);
REQUIRE(runtime != 0);

nap_bytecode_chunk* bytecode = nap_runtime_compile(runtime, 
                 "                            \
                  int a;                      \
                  a = 2;                      \
                 "
                );
REQUIRE(bytecode != 0);
int t = nap_runtime_execute(runtime, bytecode);
REQUIRE(1 == t);
REQUIRE(2 == nap_runtime_get_int(runtime, "a"));
free(runtime);
}

As it is right now it creates a runtime where it executes the code (int a; a=2;), and this works...

And I was thinking to extract the creation parts into a macro, like the one below, in a way that I have to write only the script ... so I came up with:

#define SCRIPT_START nap_runtime* runtime = nap_runtime_create(0);              \
                 nap_bytecode_chunk* bytecode = nap_runtime_compile(runtime,    \
                 "

#define SCRIPT_END  "  \
                ); \
                int t = nap_runtime_execute(runtime, bytecode); 

TEST_CASE("Variables", "[vm_variables]")
{
SCRIPT_START                    \ <<------------- HERE
    int a;                      \
    a = 2;                      \
SCRIPT_END

REQUIRE(2 == nap_runtime_get_int(runtime, "a"));
free(runtime);
}

And in my head this works nicely, but the compiler does not like it... where the HERE is it give mes the following error:

test.cpp: error: missing terminating " character

I have changed, and modified it several rotations, still the same... What do I do wrongly?

EDIT: After compiling with -E here is the relevant part:

44633     {                                                                           
44634     nap_runtime* runtime = nap_runtime_create(0); nap_bytecode_chunk* bytecode = nap_runtime_compile(runtime, "
44635         int a;                                                                  
44636         a = 2;                                                                  
44637     "                      );                     int t = nap_runtime_execute(runtime, bytecode);                     REQUIRE(1 == t);
44638

so it seems the \ from the line with the SCRIPT_START macro is being ignored ... and also the other following lines. Why?

EDIT2 Experimenting and having fun with the compiler:

Now, I put TWO backslashes:

TEST_CASE("Variables", "[vm_variables]")
{
SCRIPT_START                    \\ <<------------- HERE
    int a;                      \\
    a = 2;                      \\
SCRIPT_END

the output via -E is:

44634     nap_runtime* runtime = nap_runtime_create(0); nap_bytecode_chunk* bytecode = nap_runtime_compile(runtime, " \
44635         int a; \                                                                
44636         a = 2; \                                                                
44637     "                      );                     int t = nap_runtime_execute(runtime, bytecode);                     REQUIRE(1 == t);

and the error is almost the same:

test.cpp:19:5: error: missing terminating " character
test.cpp:19:5: error: stray ‘\’ in program

so regardless, that with two backslashes it generates "correct" code that still fails to compile :)

Upvotes: 2

Views: 1347

Answers (1)

John Kugelman
John Kugelman

Reputation: 361615

You can't have an unmatched " in a #define macro. The contents of a macro must be tokenizable. A string literal token is not a complete token if it doesn't have both begin and end quotes.

The other answers about backslashes and such are wrong. You simply cannot have unmatched quotes in macros. See this example program, which does not compile:

$ cat test.c
#include <stdio.h>

#define BEGIN_QUOTE "
#define END_QUOTE "

int main() {
    printf(BEGIN_QUOTE hello world!\n END_QUOTE);
    return 0;
}

$ gcc -Wall test.c
test.c:3:21: warning: missing terminating " character [enabled by default]
test.c:4:19: warning: missing terminating " character [enabled by default]
test.c: In function ‘main’:
test.c:7:5: error: missing terminating " character
test.c:7:24: error: ‘hello’ undeclared (first use in this function)
test.c:7:24: note: each undeclared identifier is reported only once for each function it appears in
test.c:7:30: error: expected ‘)’ before ‘world’
test.c:7:30: error: stray ‘\’ in program
test.c:7:30: error: missing terminating " character

You'll have to leave the quotes outside of the macros and write them explicitly:

SCRIPT_START
"            \
    int a;   \
    a = 2;   \
"
SCRIPT_END

Upvotes: 3

Related Questions