Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Macro expansion of __typeof__ to function name

I wrote the following code in plain C:

#define _cat(A, B) A ## _ ## B
#define cat(A, B) _cat(A, B)
#define plus(A, B) cat(cat(plus,__typeof__(A)),__typeof__(B))(A, B)

int main(int argc, const char * argv[])
{
    double x = 1, y = 0.5;
    double r = plus(x, y);
    printf("%lf",r);
    return 0;
}

Here, I would like the macro plus to be expanded becoming a function name which contains the types of the parameters. In this example I would like it to expand the following way

double r = plus(x, y)
...
/* First becomes*/
double r = cat(cat(plus,double),double)(x, y)
...
/* Then */
double r = cat(plus_double,double)(x, y)
...
/* And finally */
double r = plus_double_double(x, y)

However all I got from the preprocessor is

double r = plus___typeof__(x)___typeof(y)(x,y)

and gcc will obviously refuse to compile. Now, I know that typeof evaluates at compile-time and it is my understanding that a macro is only prevented from being evaluated when it is contained in second macro which directly involves the stringify #and the concatenation ## tokens (here's the reason why I split cat in the way you see). If this is right, why doesn't __typeof__(x) get evaluated to double by the preprocessor? Seems to me that the behaviour should be perfectly clear at build time. Shouldn't __typeof__(x) evaluate to double before even going in _cat?

I searched and searched but I couldn't find anything... Am I doing something really really stupid?

I'm running Mac OS X Mountain Lion but I'm mostly interested in getting it work on any POSIX platform.

like image 998
gianluca Avatar asked Jul 27 '13 00:07

gianluca


People also ask

What is__ typeof__ in C?

The __typeof__ operator returns the type of its argument, which can be an expression or a type. The language feature provides a way to derive the type from an expression. Given an expression e , __typeof__(e) can be used anywhere a type name is needed, for example in a declaration or in a cast.

Is there a typeof function in C?

The typeof keyword is a new extension to the C language. The Oracle Developer Studio C compiler accepts constructs with typeof wherever a typedef name is accepted, including the following syntactic categories: Declarations. Parameter type lists and return types in a function declarator.

What does the '#' symbol do in macro expansion?

The number-sign or "stringizing" operator (#) converts macro parameters to string literals without expanding the parameter definition. It's used only with macros that take arguments.


2 Answers

The reason this does not work is typeof is not a macro but a reserved word in the gcc's dialect of C and is thus handled after the preprocessor has finished its work. A good analogy would be the sizeof operator which is not a macro either and is not expanded by the preprocessor. To do (approximately) what you want (pick a different function based on the type of the arguments) try the _Generic construct (new in C11)

like image 179
alexsh Avatar answered Sep 19 '22 10:09

alexsh


Macro expansion occurs before C token analysis (see https://stackoverflow.com/a/1479972/1583175 for a diagram of the phases of translation)

The macro preprocessor is unaware of the type information -- it merely does text processing

like image 42
SheetJS Avatar answered Sep 21 '22 10:09

SheetJS