7

My problem is first of all, understanding #ifndef and #ifdef. I also want to understand the difference between #if, #ifndef , and #ifdef. I understand that #if is basically an if statement. For example:

#include<iostream>
#define LINUX_GRAPHICS 011x101

int main(){
 long Compare = LINUX_GRAPHICS;
 #if Compare == LINUX_GRAPHICS
   std::cout << "True" << std::endl;
 #endif
}

But the others, although I read about them I can't comprehend. They also seem like very similar terms, but I doubt they work similarly. Help would be greatly appreciated.

Laurel
  • 5,965
  • 14
  • 31
  • 57
amanuel2
  • 4,508
  • 4
  • 36
  • 67

5 Answers5

6

Macros are expanded by the preprocessor who doesn't know anything about values of variables during runtime. It is only about textual replacement (or comparing symbols known to the preprocessor). Your line

#if Compare == LINUX_GRAPHICS

will expand to

#if Compare == 011x101

and as "Compare" is different from "011x101", it evaluates to false. Actually I am not even 100% sure about that, but the point is: you are mixing preprocessor directives with variables that are evaluated at runtime. That is non-sense. Preprocessor directives are not there to replace C++ statements.

For most traditional use cases of macros there are better way nowadays. If you don't really need to use macros, it is better not to use them. It makes it extremely hard to read the code (eg. I don't understand how that macros in your code work and unless I really need it honestly I don't want to know :P) and there are other problems with macros that can lead to very hard to find bugs in your program. Before using macros I would advice you to first consider if there isn't a more natural C++ way of achieving the same.

PS:

#ifdef SYMBOL
    ifdef = "if defined"
    this part of the code is excluded before the compiler even sees it
    if SYMBOL is not defined (via #define)
#endif

#ifndef SYMBOL
    ifndef = "if not defined"
    this part of the code is excluded before the compiler even sees it
    if SYMBOL is defined (via #define)
#endif

I wrote "excluded" on purpose to emphasize the bad impact it has on readability of your code. If you overuse #ifdef or #ifndef inside normal blocks of code, it will be extremely hard to read.

Pengor
  • 27
  • 1
  • 7
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • What about #ifdef and #ifndef tobi? – amanuel2 May 07 '16 at 19:50
  • @Dsafds These check if the preprocessor symbol exists at all, independent of it's value (which can be empty in fact). – πάντα ῥεῖ May 07 '16 at 19:55
  • @Dsafds I added explanation of it – 463035818_is_not_an_ai May 07 '16 at 19:56
  • @tobi303 two question rose in my mind as i saw your explanation.. first : i dont see any diffrence between `#ifdef` and `#ifndef` .. and second: in a conditional preproccecor directive, you can only acess preproccecor "variables"/defined by `#define`?? – amanuel2 May 07 '16 at 19:58
  • @Dsafs the only difference is the word "not". I tried to put it in bold but that doesnt work in code blocks. Imho "access" isnt the right word. You can write `#ifdef WHATEVER` even if `WHATEVER` was not `#define`d before. One problem is that you never know what crazy symbols some other header might have defined, thus relying on `#ifndef WHATEVER` to yield true just because you didnt define it is at best dangerous. – 463035818_is_not_an_ai May 07 '16 at 20:01
  • Hmm.. im trying to think this over and connect it.. so basically `#ifndef` is like the `!` of `#ifdef`? And also, one more question so you cant change a variable defined by `#define` from other headers/files..? – amanuel2 May 07 '16 at 20:07
  • 6
    tobi303: Strictly speaking, the preprocessor works by recursively expanding all macros and replacing all non-macro symbols with `0` (*not* nothing). Then it attempts to evaluate the result as an arithmetic expression with only integer constants. The result is that `#if NOT_DEFINED == ALSO_NOT_DEFINED` will succeed; that's a classic preprocessor gotcha. – rici May 07 '16 at 20:22
  • @Dsafds _"Ok so now idk which anwser to accept.... there are like 6"_ Sigh, that's a hard decision, yes :-P ... – πάντα ῥεῖ May 07 '16 at 20:25
  • @Dsafds I know about macros only as much as I have to (which is really not a lot) and I tried to make this clear in my answer. Accept any answer you like and you think it contains enough to answer your question – 463035818_is_not_an_ai May 07 '16 at 20:51
  • @dsafds: only in the context of an #if preprocessor expression. And I didn't say macros had the value 0; they have whatever value they have. I said non-macros are replaced with a 0. – rici May 07 '16 at 22:11
5

#if doesn't have any notion about Compare or the value it contains, so it probably doesn't do what you intend.

Remember the preprocessor does plain text replacement.

The statement will expand as seen from #if as

#if Compare == 011x101

and being expanded as

#if 0 == 011x101

which certainly won't yield true at the preprocessing stage.


The #ifdef and #ifndef directives check if a preprocessor symbol was #define'd at all, either using that (<--) preprocessor directive, or your compilers preprocessor option (most commonly -D<preprocessor-symbol>).
These don't care if the preprocessor symbol carries an empty value or something. A simple

#define MY_CONDITION

or

-DMY_CONDITION

is enough to satisfy

#ifdef MY_CONDITION

to expand the text coming afterwards (or hide it with #ifndef).


The Compare declaration isn't a preprocessor symbol and can't be used reasonably with #ifdef or #ifndef either.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • so one question arrises from your explanation. preproccsing stage is the first stage of like the compiling "stuff"? or is it just before main so preprocecor conditional cant see actual variables defined as a "non-preproccecor" (Wild English there woah sorry). – amanuel2 May 07 '16 at 20:00
  • @Dsafds The preprocessing appears before _compiling_ anything. _"so preprocecor conditional cant see actual variables defined as a "non-preproccecor"_ That almost hits it. Yes, the preprocessor will see just the text `Compare` and doesn't have any notion what this will yield either at compile time or at runtime. – πάντα ῥεῖ May 07 '16 at 20:06
  • Hmm... @tobi303 's statement in his anwser comments disagree with your statements.. he says non preproccesod variables can be seen by `#ifdef` and so on.. – amanuel2 May 07 '16 at 20:09
  • "...at the preprocessing stage." Or any other stage: `011x101` is not a valid token, after preprocessing. – rici May 07 '16 at 20:09
  • 2
    @dsafds: What he says is that you can use any symbol you like in `#ifdef` (or `#ifndef`). Which is true: either the symbol has been `#define`'d, in which case `#ifdef` succeeds and `#ifndef` fails, or it has not been `#define`'d, in which case `#ifdef` fails and `#ifndef` succeeds. Whether or not that symbol will later be *declared* by the program is completely irrelevant. – rici May 07 '16 at 20:12
  • @Dsafds _"he says non preproccesod variables can be seen by #ifdef and so on."_ Huh?? Where did I say something different? `Compare` isn't a preprocessor symbol that was introduced via `#define` or the `-D` compiler option, but a variable declared in `main()`, and again the preprocessor doesn't have any notion about that. – πάντα ῥεῖ May 07 '16 at 20:12
  • @Dsafds Tried to clarify my answer about the `#ifdef`, `#ifndef` concerns. – πάντα ῥεῖ May 07 '16 at 20:22
  • Ok the anwsers have boiled down to yours and tobi. you both share the same exact thing, so i guess im going to make a random machine to guess from 0 to 1! Youll be one. whoever wins i guess gets accepted anwser – amanuel2 May 07 '16 at 20:30
  • 1
    Well I ran this code: https://github.com/amanuel2/ng-forum/blob/master/Stackoverflow/Randomizer/main.cpp i created and seems you won. Sorry for tobi, but this was pure luck. – amanuel2 May 07 '16 at 20:57
  • 1
    @Dsafds _"but this was pure luck"_ Note you missed to [`seed()`](http://stackoverflow.com/questions/1108780/why-do-i-always-get-the-same-sequence-of-random-numbers-with-rand) your random engine. I'll always win, isn't that a bit unfair? – πάντα ῥεῖ May 07 '16 at 21:03
  • Hm... let me re run this.. Ill do 3 turns this time – amanuel2 May 07 '16 at 21:10
  • Ok tobi won 3 in a row this time: https://github.com/amanuel2/C-Examples/tree/master/Stackoverflow/Randomizer – amanuel2 May 07 '16 at 21:23
  • @Dsafds _"Ok tobi won 3 in a row this time"_ That's fine, but you're still getting `srand()` wrong. It should be called once and first in your `main()` routine, best using some _random seed_ like `seed(time(NULL));` (as mentioned many times). – πάντα ῥεῖ May 07 '16 at 21:30
  • 2
    usually I get a bit bored by posts where poeple use `srand()` wrong, but this time I dont mind ;) – 463035818_is_not_an_ai May 07 '16 at 21:33
3

#if is preprocessor if. It can only deal with with preprocessor stuff which is basically preprocessor macros (which are either function like or constant-like) and C tokens with some simple integer-literal arithmetic.

#ifdef SOMETHING is the same as #if defined(SOMETHING) and #ifndef SOMETHING is the same as #if !defined(SOMETHING). defined is a special preprocessor operator that allows you to test whether SOMETHING is a defined macro. These are basically shortcuts for the most common uses or preprocessor conditionals -- testing whether some macros are defined or not.

You can find a detailed manual (~80 pages) on the gcc preprocessor at https://gcc.gnu.org/onlinedocs/ .

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
0

Basicaly, preprocessor does text substitution. Then the compiler compiles program into machine code. And then CPU executes machine instructions. This means you can't use preprocessor #if instead of operator if: one does text substitution, while second generates branching code for CPU.

So preprocessor directives such as #if, #ifdef, #ifndef serve for "semi-automatic mode" of generating (a little) different programs based on some "meta-input". Actually you can always do these substitutions yourself and get working C/C++ program without any preprocessor directives. Also compilers often have a command-line switch which outputs just preprocessed program, i.e. without any #if directives. Try to play with it, and you should get what these directives do.

#ifdef XXX is just the same as #if defined(XXX) where defined(XXX) is builtin preprocessor-only function which is true when identifier XXX is defined in program text by another preprocessor directive #define. And #ifndef XXX is just #if !defined(XXX).

Matt
  • 13,674
  • 1
  • 18
  • 27
0

Well the preprocessors #ifdef and #ifndef mean the followind: In your example you used #define to set a constant variable named LINUX_GRAPHICS to be equal to 011x101. So later in your program you migth want to check if this variable is defined. Then you use #ifdef, when you want to check if this variable is defined and #ifndef if not. I wish I helped you.