6 ms·
Here's one I recently learned about: http://reviews.llvm.org/D15866 http://reviews.llvm.org/D15866 #define FOO #define BAR defined(FOO) #if BAR
by evmar 11y ago
Here's one I recently learned about:
http://reviews.llvm.org/D15866 http://reviews.llvm.org/D15866
#define FOO
#define BAR defined(FOO)
#if BAR
...
#else
...
#endif
clang and gcc will pick the #if branch while Visual Studio will take the #else branch.
- rootbear 11y agoInteresting. I don't think I ever tried to use a macro in the conditional expression of a #if, except inside a defined() or undef(). From my time on the C committee, I recall that the preprocessor was a royal pain to get right. It has it's own set of token rules that aren't the same as C itself, for example. I am also reminded of the button I used to have that said, "Defining define is undefined."
- speeder 11y agoSTTLPORT (4.6 at least... don't checked 5.x) has lots, lots of these... I wonder how it don't crap out completely O.o
- cremno 11y agoThere are also so-called computed includes (IB instead of UB though): https://gcc.gnu.org/onlinedocs/cpp/Computed-Includes.html https://gcc.gnu.org/onlinedocs/cpp/Computed-Includes.html #define SYSTEM_H "system_1.h" ... #include SYSTEM_H
- nkurz 11y agoThis doesn't seem quite right. Did you maybe mean "#undefine FOO" or "! defined(FOO)"? Whether BAR gets expanded or not, in your example it looks like it would always evaluate true. Or am I misunderstanding the ambiguity? It might be telling that I also don't understand the Clang bug report as written. I think there are typos in the examples. Is the switch from "HAVE_FOO_BAR" to "HAVE_FOO" in the first example intentional? Is the construct "#defined" (with a final 'd') intentional in the second?
- evmar 11y agoI'm not sure -- I'm going off what the Clang bug says. They have a spec ref in there. (Note that you can't trust your intuition on how compilers work, you can only trust the spec and experiments.) If it helps any here is the real-world code where this problem came up: https://codereview.chromium.org/1584203002/ https://codereview.chromium.org/1584203002/ Edit: another reference: https://gcc.gnu.org/onlinedocs/cpp/Defined.html#Defined https://gcc.gnu.org/onlinedocs/cpp/Defined.html#Defined "If the defined operator appears as a result of a macro expansion, the C standard says the behavior is undefined."
- nkurz 11y agoOK, I've now tested. For this test code: #define FOO #define BAR defined(FOO) #if BAR #error "true" #else #error "false" #endif Clang, GCC, and ICC evaluate the "true" branch, while MSVC evaluates the "false" branch. For the same test code with first line changed to "undef": #undef FOO #define BAR defined(FOO) #if BAR #error "true" #else #error "false" #endif MSVC, Clang, GCC, and ICC all agree on "false". Importantly, though, when used with "/Wall", MSVC gives this error message in both cases: main.cpp(3): warning C4668: 'definedFOO' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' None of the other three compilers give any warnings even with '-Wall -Wextra -pedantic". So there definitely is a difference in behavior, but I don't think it's actually the one that's presumed in that bug. For further experimentation, Clang, GCC, and ICC can be tested online here: http://gcc.godbolt.org/ http://gcc.godbolt.org/ And MSVC can be tested online here: http://webcompiler.cloudapp.net/ http://webcompiler.cloudapp.net/
- bla2 11y agoAccording to the link posted by evmar, clang warns on this starting at r258128.
- cyphar 11y agoThat just looks like a Visual Studio bug to me.
- random_upvoter 11y agoThere are quite a few differences between msvc and the other compilers. For instance: #define a(x,y) x+y void f(int i) { a(i,+); } will compile without errors with cl but not with any other compiler.