I have the following code
#define PROC_ADD
void main(void)
{
while(1)
{
#ifdef PROC_ADD
// Do this code here then undefined it to run the code in the else
// processing work
#undef PROC_ADD
#else
// now that PROC_ADD has been undefined run this code
// processing work
#endif
}
}
However, it will run the code. But it won't run the code in the else after the PROC_ADD has been undefined.
I think the reason could be that you can only define and undefine at compile time, and not at run-time. However, I am not really sure.
What you are doing is the build time equivalent of:
int x = 1;
int main()
{
if (x)
{
...
x = 0;
}
else
{
...
}
}
ifdef, etc. happen at build time, but for your example, that's not an issue. Once you evaluate the if (either the runtime or build-time form), the decision about which branch to take it made. Changing something after the decision has been made does not change that decision.
The ifdef condition is evaluated when the preprocessor gets to it. When you undef PROC_ADD inside the ifdef'd code, the preprocessor has already decided which section of code to include and which to ignore.
Furthermore, yes: ifdef, undef, etc are processed at pre-processing time -- the compiler never even sees these so-called directives. This of course means run-time code never sees these directives either.
Edit: The preprocessor works by taking a single pass through the text file. The preprocessor does not even care that your text file happens to contain C code! It has zero knowledge that your ifdefs and elses and whatnot happen to be inside a while loop.
#defines only work during preprocessing. So
#define PROC_ADD
void main(void)
{
#ifdef PROC_ADD
// Do this code here then undefined it to run the code in the else
// processing work
#undef PROC_ADD
#else
// now that PROC_ADD has been undefined run this code
// processing work
#endif
}
will be processed the following way: since PROC_ADDR is defined the preprocessor will completely exclude the #else branch and then execute #undef, so the #else branch code never survives preprocessing and never reaches the compiler.
In just about every programming language or syntax, once execution has entered one branch of a conditional (in this case, the conditional being #ifdef, even if the condition changes during execution of the branch, other branches will never be executed.
I'm sure you wouldn't expect this to print "Hello", would you?
if (i == 1)
i = 0;
else
printf("Hello\n");
Basically what you're saying is that the code under the else branch should always execute, then just take it out of a branch, and put it directly in the code.
Both the compiler and the execution only make one pass through conditionals, once a match has been found they look no further.
So you want the code represented by the second comment section to always run? Why not just do
#ifdef PROC_ADD
// Do the stuff to be done if PROC_ADD is defined
#undef PROC_ADD
#endif
// Do the stuff to always be done
edit
OK - if you want run-time behaviour changes you must use run-time constructs (such as a variable to serve as a flag). As we are all saying ;), pre-processor directives are evaluated once only, at compile time.
Think about it this way: else portion of the following code is not executed even though x has been set to false in the if section.
The condition is checked in the if(x) line itself - once it enters that block, it doesn't recalculate each of the subsequent else sections - compiler has already made a decision on that.
bool x = true;
if(x)
{
//do something
x = false;
}
else
{
//else code
}
Related
I'm writing a C program that uses a custom logging function to debug my program. Whenever I compile my program as a release version, I want all of my logging functions to be stripped from the code so it won't show up if someone tries to disassemble it.
Take the following example:
#include <stdio.h>
void custom_logging_function(char* message)
{
// Do something here
}
int main()
{
custom_logging_function("Hello world"); // This call should be removed.
return 0;
}
How could I make it so that the custom_logging_function and it's arguments aren't compiled into my program without having to write include guards everywhere throughout my code? Thank you
You can use pre-processor flags, for example:
#include <stdio.h>
#ifdef DEBUG
void custom_logging_function(char* message)
{
// Do something here
}
#else
#define custom_logging_function(x) ((void) 0)
#endif
int main()
{
custom_logging_function("Hello world"); // This call should be removed.
return 0;
}
With this code you will have to tell the "debug" target to define DEBUG, if you want to define something specifically for the "release" target you can replace #ifdef DEBUG with #ifndef NDEBUG and add the NDEBUG flag to the "release" definitions.
Edit:
Changed #define custom_logging_function(x) 0 to #define custom_logging_function(x) ((void) 0) inspired by #JoachimPileborg his answer.
Assuming you only want the logging calls to happen in a debug-build of your application, and not the release build you send to customers, you can still use the preprocessor and conditional compilation for it. It can be made vert simple though by using macros instead of having checks at every call.
Something like this in a heder file:
#ifdef _DEBUG
void custom_logging_function(char* message);
#else
# define custom_logging_function(message) ((void) 0)
#endif
You could use an empty macro body for the release-macro, but that can cause some compilers to give "empty statement" warnings. Instead I use an expression casted to void (to tell the compiler that the result of the expression will not be used). Any smart compiler will not include the expression after optimization.
I find it difficult to understand the working of a macro defined with the help of preprocessor directives.
The macro,
TRXEM_SPI_BEGIN()
is defined with the help of two preprocessor directives refereed from two header files. Firstly, I wish to state the declaration of the said macro.
#define TRXEM_SPI_BEGIN() st( TRXEM_PORT_OUT &= ~TRXEM_SPI_SC_N_PIN; NOP();)
As the declaration of macro st () is missing here, I found it defined in a different header file and ti is shown below.
#define st(x) do { x } while (__LINE__ == -1)
Now after combining two macros, the true definition of macro TRXEM_SPI_BEGIN() must be,
#define TRXEM_SPI_BEGIN() do {
( TRXEM_PORT_OUT &= ~TRXEM_SPI_SC_N_PIN; NOP(); )
} while (__LINE__ == -1)
This code is written to work inside a microcontroler where TRXEM_PORT_OUT, RXEM_SPI_SC_N_PIN are memory mapped registers and NOP initiates an instruction cycle that does nothing.
As per my understanding, __LINE__ means the line of code in the c file where __LINE__ lies. That line can never be equal to -1. i.e. this loopmust always be running only once provided the __LINE__ can never be placed in -1 place in a .c file. Simply put, -1 can never be the value of __LINE__.
Therefore, I believe a do while() loop here is unnecessary and the same output could have been achieved by simply without using any looping.
I do not understand the functioning of this macro. I would so much appreciate if someone could elaborate on it.
As per my understanding, means the line of code in the c file
where __LINE__ lies. That line can never be equal to -1. i.e. this
loopmust always be running only once provided the __LINE__ can never
be placed in -1 place in a .c file. Simply put, -1 can never be the
return value to a __LINE__.
Your understanding is exactly correct here. It is there to make sure the code runs exactly once.
Think of following scenario:
#define BAZ foo();bar();
Now if you do
if(some_cond) BAZ;
This is equivalent to:
if(some_cond) foo();
bar();
Which is most possibly not something you want. So you change it to:
#define BAZ {foo();bar();}
This works fine if written as if(some_cond) foo() else wow(); but would fail compilation if written as if(some_cond) foo(); else wow();
So you define BAZ as
/* No semicolon at end */
#define BAZ do {foo();bar();} while(condition_which_is_always_false)
And you can now write the natural code with intuitive semicolon at end.
In your case, condition_which_is_always_false is __LINE__ == -1
Here is what I found in an open source project's code:
#if 0
static int print_cb(UNUSED void *ctx, void *i)
{
fprintf(stderr, "%i\n", *(int*)i);
return 0;
}
#endif
Can you explain me what's the reason for this always false if?
Thanks.
It's simply a way to use the preprocessor to comment out (prevent from compiling) a large block of code. It's pretty common.
It's better than using the actual comment syntax since it doesn't nest. If you have:
int foo = 13; /* This won't be needed. */
you can't comment it out by doing:
/*
int foo = 13; /* This won't be needed. */
*/
since the comment syntax doesn't nest, the above will not compile. Using the #if 0 method goes around that limitation.
It is a way of commenting code out. The condition will never be met (0 is never true) so the preprocessor will exclude the code from the compile.
It is typically used on bigger blocks of code that might have some embedded multi-line comments /* */ that cannot be commented out by enclosing them in another multi-line comment.
That is just to disable this code section like Multiline comment. It is better method which avoids nested comments.
From preprocessor definition here
Preprocessor directives are lines included in the code of our programs that are not program statements but directives for the preprocessor. These lines are always preceded by a hash sign (#). The preprocessor is executed before the actual compilation of code begins, therefore the preprocessor digests all these directives before any code is generated by the statements.
So, #if 0 will be decided as #if (false) (losely saying), that means, do not enter the block and skip. A way of commenting out something.
I am using a #ifdef block to conditionally include a block of code based on -Dflag passed to the compiler.
Is there a way to implement this with an if?
Something along the lines of:
if (defined(flag)) {
}
You use preprocessor to produce a different flag, which could be tested with a run-time if statement, like this:
#ifdef flag
#define flag_defined 1
#else
#define flag_defined 0
#endif
Now you can do this:
if (flag_defined) ...
If you define a macro so that it evaluates to either zero or nonzero, then you can use it in the condition of the if statement. Since it's a compile-time constant, in case it's zero, the dead code eliminator pass in the compiler will remove the unreachable code anyway.
If you are willing to give flag a value (0 or 1) instead of defining it or not, you can do
cc -Dflag=1 file.c
with
if (flag) { ... }
without messing up your code with ugly #ifdefs. You are also protected against forgetting to define flag at all: in this case your compiler treats flag as an identifier. Since you never declared it, you'll get a compile time error about an undeclared or undefined symbol flag.
No, you can't use a C if statement to check if a preprocessor token is defined.
You can use one of these forms though
#ifdef flag
...
#endif
#if defined(flag)
...
#endif
You can however check if the token evaluates to a true/false C expression,
if you use -Dflag=1 you can do
if (flag) {
...
}
And if you want to turn it off, you can define the macro as -Dflag=0
Following this you can define a new preprocessor token that you can check with a C if statement. e.g.
#ifdef flag
#define FLAG_SET 1
#else
#define FLAG_SET 0
#endif
if(FLAG_SET) { //the flag macro was defined
...
}
If all you want to do is is check whether the flag is defined, there's no point to all of this, just use #ifdef. With a C if statement, the most C compilers will optimize away the code, there's nothing you could change at runtime to get any benefit of not using the preprocessor.
#ifdef FLAG
#define FLAG_VALUE 1
#else
#define FLAG_VALUE 0
#endif
int flag = FLAG_VALUE;
...
if(flag)
{
....
}
Alternatively just use -DFLAG_VALUE=1 or -DFLAG_VALUE=0 as appropriate and use FLAG_VALUE directly.
If you plan on being able to change the FLAG_VALUE at runtime you will need a variable. If you change in non-obvious ways (e.g. via a debugger or through other loader trickery) make sure to declare it volatile, otherwise the compiler might be able to do dead-code elimination and remove huge chunks of code.
Also, if you don't plan on changing the value of flag after initializing, then you should probably make it const.
In C/C++
What happens to code placed between an #if 0/#endif block?
#if 0
//Code goes here
#endif
Does the code simply get skipped and therefore does not get executed?
Not only does it not get executed, it doesn't even get compiled.
#if is a preprocessor command, which gets evaluated before the actual compilation step. The code inside that block doesn't appear in the compiled binary.
It's often used for temporarily removing segments of code with the intention of turning them back on later.
It's identical to commenting out the block, except with one important difference: Nesting is not a problem. Consider this code:
foo();
bar(x, y); /* x must not be NULL */
baz();
If I want to comment it out, I might try:
/*
foo();
bar(x, y); /* x must not be NULL */
baz();
*/
Bzzt. Syntax error! Why? Because block comments do not nest, and so (as you can see from SO's syntax highlighting) the */ after the word "NULL" terminates the comment, making the baz call not commented out, and the */ after baz a syntax error. On the other hand:
#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif
Works to comment out the entire thing. And the #if 0s will nest with each other, like so:
#if 0
pre_foo();
#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif
quux();
#endif
Although of course this can get a bit confusing and become a maintenance headache if not commented properly.
It permanently comments out that code so the compiler will never compile it.
The coder can later change the #ifdef to have that code compile in the program if he wants to.
It's exactly like the code doesn't exist.
I'd like to add on for the #else case:
#if 0
/* Code here will NOT be complied. */
#else
/* Code will be compiled. */
#endif
#if 1
/* Code will be complied. */
#else
/* Code will NOT be compiled. */
#endif
When the preprocessor sees #if it checks whether the next token has a non-zero value. If it does, it keeps the code around for the compiler. If it doesn't, it gets rid of that code so the compiler never sees it.
If someone says #if 0 they are effectively commenting out the code so it will never be compiled. You can think of this the same as if they had put /* ... */ around it. It's not quite the same, but it has the same effect.
If you want to understand what happened in detail, you can often look. Many compilers will allow you to see the files after the preprocessor has run. For example, on Visual C++ the switch /P command will execute the preprocessor and put the results in a .i file.
Lines beginning with a # are preprocessor directives. #if 0 [...] #endif blocks do not make it to the compiler and will generate no machine code.
You can demonstrate what happens with the preprocessor with a source file ifdef.cxx:
#if 0
This code will not be compiled
#else
int i = 0;
#endif
Running gcc -E ifdef.cxx will show you what gets compiled.
You may choose to use this mechanism to prevent a block of code being compiled during the development cycle, but you would probably not want to check it in to your source control as it just adds cruft to your code and reduces readability. If it's a historical piece of code that has been commented out, then it should be removed: source control contains the history, right?
Also, the answer may be the same for both C and C++ but there is no language called C/C++ and it's not a good habit to refer to such a language.
Not quite
int main(void)
{
#if 0
the apostrophe ' causes a warning
#endif
return 0;
}
It shows "t.c:4:19: warning: missing terminating ' character"
with gcc 4.2.4
It is a cheap way to comment out, but I suspect that it could have debugging potential. For example, let's suppose you have a build that output values to a file. You might not want that in a final version so you can use the #if 0... #endif.
Also, I suspect a better way of doing it for debug purpose would be to do:
#ifdef DEBUG
// output to file
#endif
You can do something like that and it might make more sense and all you have to do is define DEBUG to see the results.