4 ms·
this is pretty basic, I would hope no actual c programmers would ask this question. Compilers are fun aren't they, how bout this one: #include <stdio.h> #d
by jfaucett 14y ago
this is pretty basic, I would hope no actual c programmers would ask this question. Compilers are fun aren't they, how bout this one:
#include <stdio.h>
#define yell(i,l,o,v,e,u) o##v##i##l
#define billy_bob yell(i,n,m,a,t,e)
billy_bob()
{
printf("no main in da house!");
}
- ntumlin 14y agoWould you please explain the code?
- deleted 14y ago[deleted]
- kevinnk 14y ago>#include <stdio.h> >#define yell(i,l,o,v,e,u) o##v##i##l defines a macro called yell. The preprocessor operator ## concatenates it's operands together so something like ma##in gets transformed into main. >#define billy_bob yell(i,n,m,a,t,e) defines a macro called billy_bob that simply expands to the macro yell. When we call yell with the given arguments we get m##a##i##n (look at the order of the arguments for yell) which gets transformed into main. >billy_bob() Expanding the macro turns this line into main(). >{ > printf("no main in da house!"); >} So now we've declared a main function that just prints "no main in da house!".
- dubya 14y agoHint: the 't' and 'e' in yell(i,n,m,a,t,e) are irrelevant.
- cnvogel 14y agoThere's the "##" operator with which you can glue together identifiers with the preprocessor. #define yell(i,l,o,v,e,u) o##v##i##l yell(i,l,o,v,e,u) will turn into the identifier ovil. And billy_bot just uses the yell-macro to produce a "main" identifier. #define billy_bob yell(i,n,m,a,t,e) yell(i,l,o,v,e,u) --> o ## v ## i ## l yell(i,n,m,a,t,e) --> m ## a ## i ## n So billy_bop is main. Why is this features useful at all? When you actually want to programmatically create function names, type names, struct names in preprocessor generated code. #define ENCAPS_STRUCT(type,name) struct encaps_##type { type name; } ENCAPS_STRUCT(int,a); will generate... $ cc -E test.c # 1 "test.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "test.c" struct encaps_int { int a; };
- habosa 14y agoOk what in the world does that do?
- marssaxman 14y agoIt's just a fancy way of assembling the identifier "main" without writing it explicitly. Inside a preprocessor macro definition, the double hash mark is an operator which concatenates its left and right operands. This is a lexical operation. The "yell" macro takes six arguments and returns the concatenation of arguments 2, 3, 0, and 1, ignoring 4 and 5. The billy_bob macro calls the yell macro, passing in some letters - if you look at which letters from "i,n,m,a,t,e" end up attached to which arguments in "yell", you'll see that "yell' rearranges 'i,n,m,a' to spell the word "main".
- whatshisface 14y agoI'm going to take a guess at this... the macros compile down to #define billy_bob main? Let's see... yell() takes six 'bare' strings and appends four of them together in a certain order while ignoring the other two. This turns (i,n,m,a,t,e) into (m,a,i,n). The second define sets billy_bob as the output of yell. I don't know C very well, is this correct?
- jfb 14y agoThat's exactly right.
- npsimons 14y agoSee, this is why I like HN. The discussion here is more interesting than the OP (which is, indeed, a very basic question that a little bit of research into the history of C would answer). I thought I knew about preprocessor magic (including stringification and variadic macros), but I'm glad to have run across this post (and the ensuing discussion) as I've learned something very useful from it (eg, how to construct more dynamic code in C/C++).
- BadDesign 14y agoI think you mean preprocessors.
- kelnos 14y agoTo be pedantic, that's just preprocessor abuse... nothing really to do with the compiler proper.