Mehrad's answer must be expanded to make it work. Also his comment
/* MYVARI(A)BLE is undefined here */
is not correct; to test for an undefined variable, there is the simple test #ifndef MYVARIABLE
.
After such test however, his expression leads to a correct solution of the original question. I tested that this code works, for undefined, defined but empty, and non-empty values of the macro MYVARIABLE:
#ifndef MYVARIABLE
/* MYVARIABLE is undefined here */
#elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
/* MYVARIABLE is defined with no value here */
#else
/* MYVARIABLE is defined here */
#endif
The #elif
statement ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
works as follows :
- When
MYVARIABLE
is defined but empty, it expands to ~(~+0) == 0 && ~(~+1) == 1
, which works out 0==0 && 1==1
(the double negation ~~ being an identity operator).
- When
MYVARIABLE
is defined to a numeric value, say n, it expands to ~(~n+0)==0 && ~(~n+1)==1
. On the left hand side of &&
, the expression ~(~n+0)==0
evaluates to n==0
. But with n==0
, the right hand side evaluates to ~(~0+1)==1
, with ~0 being -1 to ~(-1+1)==1
, then ~0==1
and finally -1==1
, which obviously is false.
- When
MYVARIABLE
is defined to a non-numeric value, the precompiler reduces all unknown symbols to 0, and we get the previous case with n==0 once more.
My complete test code (save as file test.c) :
#include <stdio.h>
int main() {
printf("MYVARIABLE is "
#ifndef MYVARIABLE
"undefined"
#elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
"defined without a value"
#else
"defined with this value : %i", MYVARIABLE
#endif
);
printf("\n");
}
With the GNU preprocessor cpp you can experiment to see what code is produced:
# undefined
cpp test.c
#defined without a value
cpp -DMYVARIABLE= test.c
#defined wit an implicit value 1
cpp -DMYVARIABLE test.c
#defined wit an explicit value 1
cpp -DMYVARIABLE=1 test.c
#defined wit an explicit value a
cpp -DMYVARIABLE=a test.c
or output of compilation and execution (under some linux)
$ gcc -o test test.c ; ./test
MYVARIABLE is undefined
$ gcc -DMYVARIABLE= -o test test.c ; ./test
MYVARIABLE is defined without a value
$ gcc -DMYVARIABLE -o test test.c ; ./test
MYVARIABLE is defined with this value : 1
$ gcc -DMYVARIABLE=1 -o test test.c ; ./test
MYVARIABLE is defined with this value : 1
$ gcc -DMYVARIABLE=a -o test test.c ; ./test
test.c: In function ‘main’:
<command-line>:0:12: error: ‘a’ undeclared (first use in this function)
...
In the last run, where MYVARIABLE is defined as 'a', the error is not an error in the macro definition; the macro is correctly lead to the last case, "defined with this value...". But this value being 'a', and 'a' not being defined in the code, the compiler or course has to signal this.
In that way, the last case is a very good example of why the intent of the original question is very dangerous: via a macro the user can introduce any sequence of program lines in the code to be compiled. Checking that such code is not introduced, requires a lot more checking of the macro on valid values. Probably a full script is needed, instead of leaving this task to preprocessing. And in that case, what is the use of checking it in preprocessing too?