even this implies some sort of back channel between the preprocessor
and the compiler. Since the preprocessor doesn't know the type
of "a" it can't simply stuff the type in place in a normal macro like
way. It looks like the maco doesn't get fully expanded until syntax
analysis
time.
No, the preprocessor doesn't implement typeof() any more than it implements
sizeof(). It just happens to be most useful in type-generic macros.
When I say
int i, j;
SWAP(i,j);
the preprocessor's output is
int i, j;
do { typeof(i) tmp; tmp=i; i=j; j=tmp; } while(0);
Understanding that "typeof(i)" means "int" is not part of preprocessing.
To come up with a similar example with sizeof(), imagine a type-generic
copy operation for reading an arbitrary value from an unaligned location, and
putting it into a properly aligned object:
#include <string.h>
/* ptr must be a char * but var can be any type */
#define GET_UNALIGNED(ptr, var) do { \
memcpy(&var, ptr, sizeof(var)); \
ptr += sizeof(var); \
} while(0)
/* Data format: 1 char, then 1 short, then 1 int, then 1 double, no padding.
Need to make them aligned properly before working on them. */
int foo(char *data)
{
char *p = data;
char c;
short s;
int i;
double d;
GET_UNALIGNED(p, c);
GET_UNALIGNED(p, s);
GET_UNALIGNED(p, i);
GET_UNALIGNED(p, d);
return d+i+s+c;
}
The macro expansion isn't delayed until the sizeof() can be evaluated. It
expands sizeof(var) to sizeof(c), sizeof(s), sizeof(i), sizeof(d), and then
the compiler does the work of turning sizeof(c) into 1, sizeof(s) into (most
likely) 2, and so on. Perfect parallel to typeof() in the other example.
(Bonus irony: I test-compiled the above with gcc and it optimized the memcpy
calls into unaligned load instructions!)