Search code examples
cgccmacrosc99iso

C - Macro contradiction


I just started learning C and I am not sure about how everything works. Some of examples simply looks weird to me and I cannot predict what would it print. I am programming in GCC, I mean it is my compiler, so every code I test is in GCC.

I understood pointers etc how that all stuff work, but also as you know there are macros. Macros are very weird, and I discovered one example I have no explanation about. For example look at this code particular code:

#include <stdio.h>

int main(void){

  #define A 1

  if(A == 0){
    #define B 1
  }

  #ifdef B
    printf("B is defined, which means that A == 0.\n");
  #elif
    printf("B isn't defined, which means that A == 1.\n");
  #endif

  printf("Value of A is %d\n", A);

  return 0;
}

What should it print? Well, I though it is easy to guess, but now I see that it is not very easy. The result is not what i thought is.

This was my reasoning: we firstly define A to be 1 and then if A is 0 then define B to be 1. So, if B is defined it means that A == 0 and otherwise A == 1. But, surprisingly it prints:

B is defined, which means that A == 0.
Value of A is 1

What? It just printed a contradiction. I am not sure if this is some weird thing in GCC (because I have no visual studio or other compiler to test it). However, I am 99% sure I somehow misunderstood macros. I tried using variables instead of macros and it works properly.

Is it an issue, or did I simply misunderstand how macros work? Please keep in mind that I'm C beginner, so take it easy :).

Thank you in advance.


Solution

  • Macros are part of the preprocessor before the code is actually compiled. The compiler will search the code for all preprocessor directives and modify the code accordingly. So when the compiler gets to if(A == 0) {#define B 1} it has already been expanded to if(0 == 1) { }.

    Macros makes it easy to configure an aspect of your code or to replace magic numbers into meaningful defines. For example:

    #define DO_HOUR_CALCULATION
    
    #define NUMBER_OF_SECONDS_PER_MINUTE (60)
    #define NUMBER_OF_SECONDS_PER_HOUR (NUMBER_OF_SECONDS_PER_MINUTE * 60)
    ...
    #ifdef DO_HOUR_CALCULATION
    int hours = time / NUMBER_OF_SECONDS_PER_HOUR;
    int minutes = (time % NUMBER_OF_SECONDS_PER_HOUR) / NUMBER_OF_SECONDS_PER_MINUTE;
    #endif // defined(DO_TIME_CALCULATION)
    

    Another use is to simplify a repeated or configurable task:

    #define DEBUG
    
    #ifdef DEBUG
    #define DPRINTF(fmt, args...) printf(fmt, ## args)
    #else
    #define DPRINTF(args...)   do {} while (0)
    #endif
    ...
    ret = read(fd, p_buffer, buf_size);
    DPRINTF("read(fd) returned %d\n", ret);
    

    Hope this helps you and happy coding!