0

I am debugging a C++ code which contains something related to Python. In a function:

void normalize(string &text) {

...

#ifdef _Python_CALL
    newContentStr = contentStr;
#endif
#ifndef _Python_CALL
   ...
   ...
#endif

return 0;

}

I am using GDB to keep track of the code logic, and I found that after it reaches the line:

newContentStr = contentStr;

It then directly jumps to the last line in the function:

return 0;

Why is the code between the following is skipped?

#ifndef _Python_CALL
       ...
       ...
    #endif

Also note that the first is "#ifdef" and the 2nd is "#ifndef". Does that make the skip?

marlon
  • 6,029
  • 8
  • 42
  • 76
  • 1
    [This question](https://stackoverflow.com/questions/3744608/the-role-of-ifdef-and-ifndef) only mentions the C preprocessor, but it works the same way in C++. – Nathan Pierson Feb 04 '22 at 01:43

2 Answers2

2

#ifndef is the opposite of #ifdef.

In your case, #ifdef is true, so it jump to return 0 directly and omit #ifndef block.

see this official doc

navylover
  • 12,383
  • 5
  • 28
  • 41
  • Thanks navylover. But what exactly mean by if _Python_CALL is true, then it skips the second block of code? The 2nd block of code is very different from the one-line first block in the #ifdef block. '_PYTHON_CALL' means if the C++ code called some python code in the first place, then it won't execute the C++ code in the 2nd block? Don't understand the logic. – marlon Feb 04 '22 at 01:53
  • @marlon all we can tell from what you provided is that in some cases there's a preprocessor symbol (so defined at compile time) called `_Python_CALL`. since the code you're debugging skips those lines it seems fairly safe to say that this symbol was not defined when the binary was compiled and so the other lines in the function weren't compiled at all. without more context it's impossible to say more. – HotelCalifornia Feb 04 '22 at 03:54
2

Judging from the code fragment you've shown, _Python_CALL is a macro name, possibly defined somewhere via #define _Python_CALL (or maybe by some other means, such as using a command line argument to the C++ compiler during compilation).

Then, line #ifdef _Python_CALL means that everything that follows it until the line #endif will be compiled (and thus executed in the compiled program) if and only if the macro name _Python_CALL is defined (the #ifdef means "if defined"). Since you claim that the line newContentStr = contentStr; was executed, we can assume that the macro name _Python_CALL was indeed defined during compilation.

Now, the line #ifndef _Python_CALL means that everything that follows it until the line #endif will be compiled (and executed) if and only if the macro name _Python_CALL is NOT defined. (Note the n in #ifndef, it means "if not defined"). But, as we already know (from the conclusion we made in the previous paragraph), this is not the case, because _Python_CALL is indeed defined. Thus, this block will not be compiled/executed.

On Cppreference, you can read more about C++ preprocessor, especially about #define and #ifdef / #ifndef directives, to gain deeper understanding.

heap underrun
  • 1,846
  • 1
  • 18
  • 22
  • Hi, heap underrun, I still have a question on this ## thing: Does it mean that in any run of of the program, the program will only execute either #if ...#endif, or #ifndef...#endif block? There is no possibility that both blocks will be executed in one run? – marlon Feb 08 '22 at 22:00
  • @marlon Yes, given the code you've shown, exactly one of those two blocks will be executed, never both (because the `_Python_CALL` macro is either defined or not defined at the point where `#ifdef _Python_CALL` is considered, and there is no `#undef _Python_CALL` before the subsequent `#ifndef _Python_CALL`, as we see). This `#ifdef _Python_CALL … #endif #ifndef _Python_CALL … #endif` construct seems equivalent to just `#ifdef _Python_CALL … #else … #endif` (if there's no other preprocessor directives in-between that you didn't show). Hard to guess the purpose of the macro w/o further details. – heap underrun Feb 09 '22 at 04:32
  • @marlon BTW, the whole preprocessor stuff is not about any particular run of the program. This is about compilation. Preprocessor directives are commonly used for conditional compilation: for example, to specify that "on Windows do this / on Unix do that". Once the source code is compiled (+ linked) into an executable, the stuff that was filtered out (due to `#ifdef` / `#ifndef` skipping some blocks) will not be even there at all, i.e., the executable will not even contain the machine instructions corresponding to the blocks filtered out by the preprocessor. – heap underrun Feb 09 '22 at 04:32
  • @marlon Also, just noticed, the code fragment you've shown has a bug: the function is declared `void`, so it is not supposed to return a value, but there is `return 0;` at the end. This will not compile, or perhaps the compiler will emit a warning at least! – heap underrun Feb 09 '22 at 04:33
  • Thanks for the detailed explanation, and it's very helpful. – marlon Feb 09 '22 at 22:21