Reason for always false directive if in C - c

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.

Related

Print a deprecation warning when using a macro in a #if statement

I want to deprecate a macro in such a way that it will print a nice warning even if used inside of a #if statement.
This answer is very nearly what I want, but it throws an error when the macro is accessed from within a #if statement.
#include <stdio.h>
#define DEPRECATED_CONSTANT _Pragma ("GCC warning \"Deprecated constant!\"") 0
#define DEPRECATED_FUNCTION(...) _Pragma ("GCC warning \"Deprecated function!\"") printf(__VA_ARGS__)
int main() {
// Prints a warning (good)
int n = DEPRECATED_CONSTANT;
// Prints a warning (good)
DEPRECATED_FUNCTION("%d\n", n);
// Throws an error (bad)
#if DEPRECATED_CONSTANT
return 1;
#else
return 2;
#endif
}
The error is:
error: missing binary operator before token "("
Bonus points if you can find me a cross-platform compatible solution!
EDIT
I'm trying to handle a breaking change in a library gracefully - I want users to have a nice, clear warning (or error) whenever they use an old macro, so it will be clear that they need to migrate their code to using the new macro. These pragma solutions only work if the value of that constant is used in code, not if the value is accessed in a preprocessor directive.
According to the answers provided below, it seems like there's not a solution to this problem (except possibly when using clang?). Thanks, everyone.
I want to deprecate a macro in such a way that it will print a nice
warning even if used inside of a #if statement.
I was going to suggest the comma operator, but that doesn't seem to work because the _Pragma macro probably yields no real code. Also, gcc, at least, explicitly says you can't do what you suggested with _Pragma():
https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html
The standard is unclear on where a _Pragma operator can appear. The
preprocessor does not accept it within a preprocessing conditional
directive like ‘#if’. To be safe, you are probably best keeping it out
of directives other than ‘#define’, and putting it on a line of its
own.
PS - clang 8.1.0 didn't error on your program and gave the warnings you want ...
As #jschultz410 mentions, what you are trying to do is explicitly forbidden in gcc (see https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html).
Nested macros seem appropriate for such a use case:
#include <stdio.h>
#define DEPRECATED_CONSTANT_VALUE 0
#define DEPRECATED_CONSTANT _Pragma ("GCC warning \"Deprecated constant!\"") DEPRECATED_CONSTANT_VALUE
#define DEPRECATED_FUNCTION(...) _Pragma ("GCC warning \"Deprecated function!\"") printf(__VA_ARGS__)
int main() {
// Prints a warning (good)
int n = DEPRECATED_CONSTANT;
// Prints a warning (good)
DEPRECATED_FUNCTION("%d\n", n);
// Throws an error (bad)
#if DEPRECATED_CONSTANT_VALUE
return 1;
#else
return 2;
#endif
}
Yes, this is kind of gross, but in the land of preprocessor logic we're already giving up on any kind of design elegance in the first place. At least this way the macro interface is maintained in non-preprocessor code. (Yes, this would not print the preprocessor warning in the #if statement, but unfortunately that's not possible with gcc).

Preprocessor directives in C : macros using __LINE__

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

C-Macro in if-Condition

quite a simple problem I have here.
I have a little Macro for a global Variable which is defined in my Header like this:
extern bool uart_message_received;
#define get_uart_message_rec() uart_message_received;
In my C-File I want to access the file like this:
bool uart_message_received = 0;
void foo(void)
{
bool test;
test = get_uart_message_rec(); // Works fine
if(get_uart_message_rec()==0) // Doesn't work
{
//...
}
}
I am a little confused why the condition in the if is not working. Am I doing something wrong, or am I violating some C directives?
#define get_uart_message_rec() uart_message_received
// ^ no semicolon
Macro replacement will substitute the text as is, including the ; in your case. Which will lead to syntax errors in the if case.
Remove the colon at the end of :
#define get_uart_message_rec() uart_message_received;
Because it becomes:
if(**uart_message_received;**==0) // Doesn't work
{
//...
}
When the preprocessor basically does find/replace on your code.
You have a semicolon on the end of your macro - remove that, and it will be fine. Note that macros do replace exactly as written, so your macro expands from:
if(get_uart_message_rec()==0)
to:
if(uart_message_received; ==0)
which should make the compiler error.
[writing too slowly!]
It's because you have a semicolon at the end of the macro.
Macros are replaced as is, before the actual compiler sees the text, so the statement after replacement looks like this:
if(uart_message_received;==0)

What exactly does an #if 0 ..... #endif block do?

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.

#define, #ifdef #undef #endif

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
}

Resources