"if " and " #if "; which one is better to use [duplicate] - c

This question already has answers here:
Difference between preprocessor directive #if and normal if
(3 answers)
Closed 9 years ago.
I learned that if or #if can both be used for condition checks.
As we can check conditions using if, why would we use preprocessor #if?
What difference will it make to my code if I use #if instead of if?
Which one is better to use and why?

if and #if are different things with different purposes.
If you use the if statement, the condition is evaluated at runtime, and the code for both branches exists within the compiled program. The condition can be based on runtime information, such as the state of a variable. if is for standard flow control in a program.
If you use the preprocessor's #if, the condition is evaluated at compile-time (originally this was before compile-time, but these days the preprocessor is usually part of the compiler), and the code for the false branch is not included in the compiled program. The condition can only be based on compile-time information (such as #define constants and the like). #if is for having different code for different compile-time environments (for instance, different code for compiling on Windows vs. *nix, that sort of thing).

we could not say which better to use, because one is used in the compilation phase (#if) and the other one is used in the runtime phase(if)
#if 1
printf("this code will be built\n");
#else
printf("this code will not\n");
#endif
try to build the above code with gcc -E and you will see that your compiler will generate another code containing only :
printf("this code will be build\n");
the other printf will not be present in the new code (pre processor code) and then no present in the program binary.
Conclusion: the #if is treated in the compilation phase but the normal if is treated when your program run
You can use the #if 0 in a part of your code inorder to avoid the compiler to compile it. it's like you have commented this part
example
int main(void) {
printf("this code will be build\n");
#if 0
printf("this code will not\n");
#endif
}
it's equivalent to
int main(void) {
printf("this code will be built\n");
/*
printf("this code will not\n");
*/
}

Hey both are different
#if Tests if the condition is true at the compile time.
if is evaluated at runtime.

You should use #if when the outcome of the condition is known at compile time and regular if when outcome is not known until runtime.
#if DEBUG
I know at compile time I am making a debug build
if (date == DateTime.Today)
Depends on what day it is

Some uses of #if are:
You want to put extra prints, or checks when you build a debug version of your code
you want to ensure the compiler doesn't include a .h file twice
you want to write code that will use different system calls, and depending on the system it gets compiled on use the appropriate ones.
Because all of the above are checked at compile time this means that:
The condition must be able to be evaluated at compiletime
The produced code will not contain the branches that evaluate to false, leading to smaller code, and faster, as the condition is not checked every time the program is run.
Examples:
Adding extra checks only for debug mode:
#define DEBUGLEVEL 2
#if DEBUGLEVEL > 1
printf("The value of x is: %d", x);
#end if
#if DEBUGLEVEL > 2
printf("The address of x is: %x", &x);
ASSERT(x > 100);
#end if
Ensuring header only gets included once:
#ifndef PERSON_H
#define PERSON_H
class Person{
....
};
#end if
Having different code depending on platform:
#ifdef WINDOWS
time = QueryPerformanceCounter(..);
#else
time = gettimeofday(..);
#endif

Related

Check directory exists or not in C, Using preprocessor

I wanted to #define some macros based on whether particular directory is present in Linux, I can't use any fopen/directory/stat API's here since they are exposed during compilation phase
Example,
Need to set
---->Someway to check directory existing using C macro, i.e before compilation phase
#define RANDOM 100
#else
#define RANDOM 200
Need help here.
You can define a macro from the command line using the -D preprocessor option, in your case:
gcc -o demo demo.c -DRANDOM=$(test -d /path/to/some/dir && echo 100 || echo 200)
You simply read RANDOM from your program:
#include <stdio.h>
int main(void)
{
printf("%d\n", RANDOM);
}
You can't do this as the preprocessor textually replaces one value with another (more precisely it replaces tokens). It is done before the actual C code compilation.
You need to have variable RANDOM (not macro definition) and assign it with the value runtime.
int RANDOM = 0;
if(directory_exists(directory))
{
RANDOM = 200
}
else
{
RANDOM = 500
}
and use it later in your code.

Will the compiler allocate any memory for code disabled by macro in C language?

For example:
int main()
{
fun();//calling a fun
}
void fun(void)
{
#if 0
int a = 4;
int b = 5;
#endif
}
What is the size of the fun() function? And what is the total memory will be created for main() function?
Compilation of a C source file is done in multiple phases. The phase where the preprocessor runs is done before the phase where the code is compiled.
The "compiler" will not even see code that the preprocessor has removed; from its point of view, the function is simply
void fun(void)
{
}
Now if the function will "create memory" depends on the compiler and its optimization. For a debug build the function will probably still exist and be called. For an optimized release build the compiler might not call or even keep (generate boilerplate code for) the function.
Compilation is split into 4 stages.
Preprocessing.
Compilation.
Assembler.
Linker
Compiler performs preprocessor directives before starting the actual compilation, and in this stage conditional inclusions are performed along with others.
The #if is a conditional inclusion directive.
From C11 draft 6.10.1-3:
Preprocessing directives of the forms
#if constant-expression new-line groupopt
#elif constant-expression new-line groupopt
check whether the controlling constant expression evaluates to nonzero.
As in your code #if 0 tries to evaluate to nonzero but remains false, thereby the code within the conditional block is excluded.
The preprocessing stage can be output to stdout with -E option:
gcc -E filename.c
from the command above the output will give,
# 943 "/usr/include/stdio.h" 3 4
# 2 "filename.c" 2
void fun(void)
{
}
int main()
{
fun();
return 0;
}
As we can see the statements with the #if condition are removed during the preprocessing stage.
This directive can be used to avoid compilation of certain code block.
Now to see if there is any memory allocated by the compiler for an empty function,
filename.c:
void fun(void)
{
}
int main()
{
fun();
return 0;
}
The size command gives,
$ size a.out
text data bss dec hex filename
1171 552 8 1731 6c3 a.out
and for the code,
filename.c:
void fun(void)
{
#if 0
int a = 4;
int b = 5;
#endif
}
int main()
{
fun();
return 0;
}
The output of size command for the above code is,
$ size a.out
text data bss dec hex filename
1171 552 8 1731 6c3 a.out
As seen in both cases memory allocated is same by which can conclude that the compiler does not allocate memory for the block of code disabled by macro.
According to Gcc reference:
The simplest sort of conditional is
#ifdef MACRO
controlled text
#endif /* MACRO */
This block is called a conditional group. controlled text will be
included in the output of the preprocessor if and only if MACRO is
defined. We say that the conditional succeeds if MACRO is defined,
fails if it is not.
The controlled text inside of a conditional can include preprocessing
directives. They are executed only if the conditional succeeds. You
can nest conditional groups inside other conditional groups, but they
must be completely nested. In other words, ‘#endif’ always matches the
nearest ‘#ifdef’ (or ‘#ifndef’, or ‘#if’). Also, you cannot start a
conditional group in one file and end it in another.
Even if a conditional fails, the controlled text inside it is still
run through initial transformations and tokenization. Therefore, it
must all be lexically valid C. Normally the only way this matters is
that all comments and string literals inside a failing conditional
group must still be properly ended.
The comment following the ‘#endif’ is not required, but it is a good
practice if there is a lot of controlled text, because it helps people
match the ‘#endif’ to the corresponding ‘#ifdef’. Older programs
sometimes put MACRO directly after the ‘#endif’ without enclosing it
in a comment. This is invalid code according to the C standard. CPP
accepts it with a warning. It never affects which ‘#ifndef’ the
‘#endif’ matches.
Sometimes you wish to use some code if a macro is not defined. You can
do this by writing ‘#ifndef’ instead of ‘#ifdef’. One common use of
‘#ifndef’ is to include code only the first time a header file is
included.

C code after preprocessor

This is an exercise taken by a book. The question is what is the output of this code.
This code prints always "N is undefined", but I don't know why. The command "#undef N" is after the function f. Then, why the output is always "N is undefined"?
#define N 100
void f(void);
int main(void)
{
f();
#ifdef N
#undef N
#endif
return 0;
}
void f(void)
{
#if defined(N)
printf("N is %d\n", N);
#else
printf("N is undefined\n");
#endif
}
The point of this exercise is to demonstrate that preprocessor's control flow is completely separate from the control flow of your program.
#if/#undef directives are processed in the order that they appear in the text of your program. They are processed only once at compile time; the decision to define or undefine a preprocessor variable cannot be reconsidered at runtime.
That's why the fact that f executes before #if/#undef line of the main is irrelevant. You can change the output of this program only by moving f to a position in file before main.
If you run the compiler with the -E flag (for gcc at least) it'll show you what the code you're actually compiling is.
You'll see that the preprocessor doesn't follow the code execution - it performs its actions in the order that they appear in the file.
Then the compiler takes the resulting code and f just has the one call to printf in it that says N isn't defined.
The C preprocessor goes through your code line by line. As such, it is wrong to assume the #undef happens after the function f() because of the function call. Instead, it happens before your definition of function f().
To understand this, you have to distinguish between the preprocessor (line by line) and the control flow (follows function calls).
Because the preprocessors instructions run in the "physycal" order, line after line.
Think about it something is executed before actual compilation, in a such way your code be clear, only with plain C code for the compiler.

if 0 is compiled in c program

I'm trying to removed unused code from my program - I can't delete the code for now, I just want to disable it for a start.
Let's say that I have the following code:
if (cond){
doSomething()
}
and cond is always false so doSomething is never called.
I want to do something like:
#define REMOVE_UNUSED_CODE 0
if (cond && REMOVE_UNUSED_CODE){
doSomething()
}
Now this is obvious to us (and hopefully for the compiler) that this code is unused.
Will the compiler remove all this if condition or it will leave it and never get in?
P.S.: I can't use #if 0 for this purpose
GCC will explicitly remove conditional blocks that have a constant expression controlling them, and the GNU coding standards explicitly recommend that you take advantage of this, instead of using cruder methods such as relying on the preprocessor. Although using preprocessor #if may seem more efficient because it removes code at an earlier stage, in practice modern optimizers work best when you give them as much information as possible (and of course it makes your program cleaner and more consistent if you can avoid adding a phase-separation dependency at a point where it isn't necessary).
Decisions like this are very, very easy for a modern compiler to make - even the very simplistic TCC will perform some amount of dead-code elimination; powerful systems like LLVM and GCC will spot this, and also much more complex cases that you, as a human reader, might miss (by tracing the lifetime and modification of variables beyond simply looking at single points).
This is in addition to other advantages of full compilation, like the fact that your code within the if will be checked for errors (whereas #if is more useful for removing code that would be erroneous on your current system, like references to nonexistent platform functions).
Try
#ifndef REMOVE_UNUSED_CODE
if (cond) {
doSomething();
}
#endif
Instead.
Don't forget to do a
#define REMOVE_UNUSED_CODE
somewhere.
The answer depends on the implementation of the compiler. You should never depend on this.
Instead be explicit:
#define REMOVE_UNUSED_CODE 0
if (cond && REMOVE_UNUSED_CODE){
#ifndef REMOVE_UNUSED_CODE
doSomething()
#endif
}
Looking at this snippet of your code
#define REMOVE_UNUSED_CODE 0
if(cond && REMOVE_UNUSED_CODE)
{
doSomething();
}
REMOVE_UNUSED_CODE is replaced with 0 by preprocessor before compilation.
So if(cond && 0) will always be evaluated as false and will never be executed. So you can say, irrespective of what cond is, it will always be false.
So I'd rather prefer it doing this way:
//#define REMOVE_UNUSED_CODE 0
#ifdef REMOVE_UNUSED_CODE
if(cond)
{
doSomething();
}
#endif
You should not do it that way:
Suppose you have a function bool f(void* input) with side effects.
Then with
if( f(pointer) && false ) { ... }
the body is not evaluated, but f should be.
In the case of
if( false && f(pointer) ) { ... }
f is not evaluated because of the short-cut rule of the &&operator.
If you use
#define REMOVE_UNUSED_CODE
#ifndef REMOVE_UNUSED_CODE
if( f(pointer) && false ) { }
#endif
the whole code is not even compiled in and will never be executed.
Not a direct answer, but may be helpful. There are compiler-specific intrinsics to do code removal.
For MSVC, it is __assume(0)
For GCC/Clang, it is __builtin_unreachable().
Notice, however, that if you write something like:
if (cond){
__builtin_unreachable();
doSomething()
}
Your condition should never evaluate to true, otherwise behavior is undefined.
Combining both && REMOVE_UNUSED_CODE and __builtin_unreachable() ensures that your code will be removed by the compiler.

warning: unused variable

see in one code i have written
void my_function()
{
INT32 i; /* Variable for iteration */
/* If system is little-endian, store bytes in array as reverse order */
#ifdef LITTLE
{
// i m using i for operating one loop
}
#endif
/* If the system is big-endian, store bytes in array as forward order */
#ifdef BIG
{
// using i for loop
}
#endif
return;
}
by compiling this code with -Wall flag it shows
warning: unused variable ‘i’
why?
how can i remove this?
Put the declaration of i just inside the {} where you actually use it. Even better if you have C99, declare the loop variable inside the for(int i = 0, i < bound; ++i)
By defining either LITTLE or BIG. I doubt many compilers give that warning for this code when one of those symbols are defined. If you still have the warning, then you might change the second #ifdef to an #else.
I don't see any #endif anywhere -- presumably in the real code, those appear.
You need to define either BIG or LITTLE (as mentioned elsewhere).
In order to stop this happening again in the future, you can raise a specific compile-time error using the following:
#if !defined LITTLE && !defined BIG
#error You haven't defined one of your macro names
#endif
Alternatively, you could include i only when using either code block by surrounding it with #if defined as well:
#if defined LITTLE || defined BIG
INT32 i;
#endif
In both cases, note the keyword to use is #if not #ifdef or #ifndef.
You do not have to declare the iteration number. Just do it in your for statement.
for(int i = 0; i < 6; i++){
// insert loop code here
}
hey i got the answer...
see BIG & LITTLE are preposser flag & they are given at compile time.
when i was compiling my project with make file i was giving this flag at compile time but while testing each individual file i was compiling like
gcc -Wall -c filename.c
This was comming because i havent given any flag so compiler going to neglet that much portion of code & i was getting warning.
gcc -Wall -c -LITTLE filename.c
works perfectly...

Resources