3

Unless my understanding is incorrect, the following macro

int i; // for loop
const char* ctype; // proprietary type string
void** pool = malloc(sizeof(void*) * (nexpected - 1));
size_t poolc = 0;

#define SET(type, fn) type* v = (pool[poolc++] = malloc(sizeof(type)));         \
    *v = (type) fn(L, i)
#define CHECK(chr, type, fn) case chr:                                          \
    SET(type, fn);                                                              \
    break

switch (ctype[0]) {
  CHECK('c', char, lua_tonumber);
}

should expand to

int i; // for loop
const char* ctype; // proprietary type string
void** pool = malloc(sizeof(void*) * (nexpected - 1));
size_t poolc = 0;

switch (ctype[0]) {
  case 'c':
    char* v = (pool[poolc++] = malloc(sizeof(char)));
    *v = (char) lua_tonumber(L, i);
    break;
}

but upon compilation, I get:

src/lua/snip.m:185:16: error: expected expression
    CHECK('c', char, lua_tonumber);
               ^
src/lua/snip.m:181:9: note: expanded from macro 'CHECK'
    SET(type, fn);                                                              \
        ^
src/lua/snip.m:178:23: note: expanded from macro 'SET'
#define SET(type, fn) type* v = (pool[poolc++] = malloc(sizeof(type)));         \
                      ^
src/lua/snip.m:185:5: error: use of undeclared identifier 'v'
    CHECK('c', char, lua_tonumber);
    ^
src/lua/snip.m:181:5: note: expanded from macro 'CHECK'
    SET(type, fn);                                                              \
    ^
src/lua/snip.m:179:6: note: expanded from macro 'SET'
    *v = (type) fn(L, i)
     ^
2 errors generated.

What is going on here? Isn't the preprocessor a literal text replacement engine? Why is it trying to evaluate expressions?

Keep in mind while this looks like straight C, this is actually clang Objective C (note the .m) under the C11 standard. Not sure if that makes any difference.

I'm a loss at how to continue without expanding the code for each entry.

Qix - MONICA WAS MISTREATED
  • 14,451
  • 16
  • 82
  • 145
  • @Lundin if you read the OP, it'd tell you. – Qix - MONICA WAS MISTREATED Jan 28 '15 at 07:50
  • The C11 tag should be used for questions that use features that are specific to the C11 standard, which is not the case here. If you read the tag wiki, it'd tell you. – Lundin Jan 28 '15 at 07:52
  • @Lundin I'm well aware of how tags work. I'm compiling against the C11 standard. After the answer, it is clear it is not a C11 issue. However, when I asked I didn't know if C11 had changed how macros worked. It was pertinent to the question at the time. You're welcome to search Meta regarding C/C++ related 'tag-nazi' discussions. – Qix - MONICA WAS MISTREATED Jan 28 '15 at 07:53
  • You could always just remote the tag from your post instead of leaving snide comments. It is not the end of the world. – Lundin Jan 28 '15 at 07:55
  • @Lundin and if you looked at the OP, you would have seen that I did. Thank you for your concern. – Qix - MONICA WAS MISTREATED Jan 28 '15 at 07:56

1 Answers1

5

Your understanding is correct! But you're running into a quirk of the C language. A label, including a case label, must be followed by an expression, not a variable declaration.

You can work around this by inserting a null statement (e.g, 0;) after the case, or by enclosing the case body in a set of braces. A practical way of doing this might be by redefining CHECK as:

#define CHECK(chr, type, fn) \
    case chr: { SET(type,fn); } break;
Community
  • 1
  • 1