I need to make some code in a sketch be executed depending on the contents of another #define
In my case, I want to be able to use the contents of IDENTIFIER to decide whether to excecute parts of code in my sketch.
In the case below, if IDENTIFIER = C then code between #ifdef TEST and # endif need to be executed. But this code here does not compile.
... how to accomplish?
#define IDENTIFIER 'C'
void setup() {
Serial.begin(9600);
delay(100);
Serial.println(__FILE__);
Serial.println(" ");
Serial.println("Arduino_ifdef-test");
if (IDENTIFIER == 'C') {
#define TEST;}
#ifdef TEST
Serial.println(F("ifdef TEST print"));
#endif
}
void loop() {
}
Did you actually try that with IDENTIFIER set to something besides 'C'?
The #define is a pre-processor directive, and will be unaffected by the if statement, which executes at run-time, or in this case will be totally removed by the compiler during optimization.
@J-M-L Indeed this works too, but using #ifdef and #endif is going to make my code more readible since I am using this condition on multiple instances in my code for multiple code lines.
And this is needed (I tested without and does not work):
#else
#undef TEST
#endif
@van_der_decken Thank you for that very fast answer and solution.
Of course it will, we're talking about assembling code at the compilation stage depending on the directives, but this can be done in different ways, the result will most likely be the same
PS I was wrong, the compiler won't throw out the #define TEST at the build stage, and everything won't go according to plan
Apparently I hadn't woken up yet.
If it does not work it would mean someone else is defining TEST… That’s weird as when compiling an Arduino .ino sketch, the build system automatically defines several macros related to the board’s type, frequency, file names, dates and core but I’m not aware of TEST being defined...
#define IDENTIFIER 'C'
void setup() {
Serial.begin(9600);
// :
if (IDENTIFIER == 'C') {
Serial.println(F("ifdef TEST print"));
}
Will do an equally good job of conditionally omitting the code inside the if statement. The logical statement will expand to if ('C' == 'C') and hanks to compiler optimization, the code will just be left out of the binary.
I'm of somewhat mixed opinions on whether this sort of conditional compilation make the code easier or harder to read (on the one hand, the preprocessor is losing popularity, and it's nice to avoid it . On the other hand, it makes it harder to distinguish dynamic code from static code.)
The most interesting use I've seen of this technique was like:
if (pak_is_scattered(networkPacket)) {
// merge the scattered bits of packet into contiguous memory
}
where pak_is_scattered(p) was defined as some relatively deep inspection (maybe a function call, like it looks?) of the packet structure IFF the platform being compiled supported scattered packets. On platforms that didn't support scattering, there was #define pak_is_scattered(p) 0, and the merge code would never be included...
Preprocessor directives are part of the language and guarantee that excluded code is never even compiled. So I still prefer to rely on macros when it comes to conditional compilation. It makes things totally clear and deterministic — the code is either there or it isn’t.
Relying on the optimizer to remove a branch means depending on compiler heuristics instead of explicit intent ➜ you need to take into consideration that the optimizer behavior varies with flags, versions, and build types which are not part of the code, while preprocessor logic is fixed and entirely under the programmer’s control. It’s also at a different stage: the optimizer works after parsing, so the code must still compile and type-check even if it’s later removed, whereas #if prevents it from existing in that translation unit at all ➜ that avoids unnecessary symbol resolution and potential linkage issues.