Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compound literals and function-like macros: bug in gcc or the C standard?

In C99, we have compound literals, and they can be passed to functions as in:

f((int[2]){ 1, 2 });

However, if f is not a function but rather a function-like macro, gcc barfs on this due to the preprocessor parsing it not as one argument but as two arguments, "(int[2]){ 1" and "2 }".

Is this a bug in gcc or in the C standard? If it's the latter, that pretty much rules out all transparent use of function-like macros, which seems like a huge defect...

Edit: As an example, one would expect the following to be a conforming program fragment:

fgetc((FILE *[2]){ f1, f2 }[i]);

But since fgetc could be implemented as a macro (albeit being required to protect its argument and not evaluate it more than once), this code would actually be incorrect. That seems surprising to me.

like image 677
R.. GitHub STOP HELPING ICE Avatar asked Apr 05 '11 20:04

R.. GitHub STOP HELPING ICE


2 Answers

This "bug" has existed in the standard since C89:

#include <stdio.h>

void function(int a) {
    printf("%d\n", a);
}

#define macro(a) do { printf("%d\n", a); } while (0)

int main() {
    function(1 ? 1, 2: 3); /* comma operator */
    macro(1 ? 1, 2: 3);    /* macro argument separator - invalid code */
    return 0;
}

I haven't actually looked through the standard to check this parse, I've taken gcc's word for it, but informally the need for a matching : to each ? trumps both operator precedence and argument list syntax to make the first statement work. No such luck with the second.

like image 65
Steve Jessop Avatar answered Sep 17 '22 17:09

Steve Jessop


This is per the C Standard, similar to how in C++, the following is a problem:

f(ClassTemplate<X, Y>) // f gets two arguments:  'ClassTemplate<X' and 'Y>'

If it is legal to add some extra parentheses there in C99, you can use:

f(((int[2]){ 1, 2 }));
  ^                ^

The rule specifying this behavior, from C99 §6.10.3/11, is as follows:

The sequence of preprocessing tokens bounded by the outside-most matching parentheses forms the list of arguments for the function-like macro.

The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate arguments.

like image 30
James McNellis Avatar answered Sep 19 '22 17:09

James McNellis