Search code examples
macrosc-preprocessorpragma

Expand C preprocessor ternary macro for printing in pragma message?


Judging by this Print numeric value of a define that's based on other macros via pragma message? , what I want is likely not possible; then again, I'm not doing arithmetic here - so here is my example:

#include <stdio.h>
enum my_sizes { SIZE_BITS_8 = 0, SIZE_BITS_16 = 1, SIZE_BITS_32 = 2 };

#define XSTR(x) STR(x)
#define STR(x) #x

#define CHOSEN_SIZE_BITS SIZE_BITS_32
#define CHOSEN_SIZE_BYTES \
    ( CHOSEN_SIZE_BITS==SIZE_BITS_8 ? 1  \
      : CHOSEN_SIZE_BITS==SIZE_BITS_16 ? 2 \
      : CHOSEN_SIZE_BITS==SIZE_BITS_32 ? 4 \
      : 0 )

#pragma message( "CHOSEN_SIZE_BITS " XSTR(CHOSEN_SIZE_BITS) " CHOSEN_SIZE_BYTES " XSTR(CHOSEN_SIZE_BYTES) )

int main() {
    printf("Hello, world! bytes: %d!\r\n", CHOSEN_SIZE_BYTES);
    return 0;
}

In https://replit.com/languages/c, this produces:

> clang-7 -pthread -lm -o main main.c
main.c:14:9: warning: CHOSEN_SIZE_BITS SIZE_BITS_32
      CHOSEN_SIZE_BYTES ( SIZE_BITS_32==SIZE_BITS_8 ? 1 :
      SIZE_BITS_32==SIZE_BITS_16 ? 2 :
      SIZE_BITS_32==SIZE_BITS_32 ? 4 : 0 )
      [-W#pragma-messages]
#pragma message( "CHOSEN_SIZE_BITS " XSTR(CHOSEN_SIZE_...
        ^
1 warning generated.
> ./main
Hello, world! bytes: 4!
> 

What I wanted instead, was the printout of pragma message to be:

main.c:14:9: warning: CHOSEN_SIZE_BITS 2 CHOSEN_SIZE_BYTES 4

Note that XSTR would have expanded CHOSEN_SIZE_BITS to a number, in case it was defined via #define CHOSEN_SIZE_BITS 2, but it seemingly doesn't if an enum value is used in the define; and of course, the whole ternary expression is included in the pragma message printout - even if the C printout (via printf) confirms that the CHOSEN_SIZE_BYTES does indeed end up with the expected value 4.

So, is it somehow possible to get the printout that I want from the above macros - and if so, how?


Solution

  • To calculate something in preprocessor you have to calculate it in preprocessor. Ternary is evaluated at runtime. In preprocessor you have macro expansions and ## operator and then some more macro expansions and ## operator. Nothing more.

    The following code:

    #define SIZE_BITS_8   0
    #define SIZE_BITS_16  1
    #define SIZE_BITS_32  2
    
    #define XSTR(x) STR(x)
    #define STR(x) #x
    
    #define BITS_TO_BYTE_0()  1
    #define BITS_TO_BYTE_1()  2
    #define BITS_TO_BYTE_2()  4
    #define BITS_TO_BYTE_IN(SIZE_BITS)  \
            BITS_TO_BYTE_##SIZE_BITS()
    #define BITS_TO_BYTE(SIZE_BITS)  \
            BITS_TO_BYTE_IN(SIZE_BITS)
    
    
    #define CHOSEN_SIZE_BITS   SIZE_BITS_32
    #define CHOSEN_SIZE_BYTES  BITS_TO_BYTE(CHOSEN_SIZE_BITS)
    
    #pragma message( "CHOSEN_SIZE_BITS " XSTR(CHOSEN_SIZE_BITS) " CHOSEN_SIZE_BYTES " XSTR(CHOSEN_SIZE_BYTES) )
    

    Outputs the following diagnostic on GCC:

    <source>:22:9: note: '#pragma message: CHOSEN_SIZE_BITS 2 CHOSEN_SIZE_BYTES 4'
       22 | #pragma message( "CHOSEN_SIZE_BITS " XSTR(CHOSEN_SIZE_BITS) " CHOSEN_SIZE_BYTES " XSTR(CHOSEN_SIZE_BYTES) )