Search code examples
cboost-preprocessor

Mixing variables and integer constants in the Boost Preprocessor


I am using BOOST_PP for to do precompile computations in the preprocessor. I am focusing on an application where code size is extremely important to me. (So please don't say the compiler should or usually does that, I need to control what is performed at compile time and what code is generated). However, I want to be able to use the same name of the macro/function for both integer constants and variables. As trivial example, I can have

#define TWICE(n) BOOST_PP_MUL(n,2)
//.....
// somewhere else in code
int a = TWICE(5);

This does what I want it to, evaluating to

int a = 10;

during compile time.

However, I also want it to be used at

int b = 5;
int a = TWICE(b);

This should be preprocessed to

int b = 5;
int a = 5 * 2;

Of course, I can do so by using the traditional macros like

#define TWICE(n) n * 2

But then it doesnt do what I want it to do for integer constants (evaluating them during compile time).

So, my question is, is there a trick to check whether the argument is a literal or a variable, and then use different definitions. i.e., something like this:

#define TWICE(n) BOOST_PP_IF( _IS_CONSTANT(n), \
                              BOOST_PP_MUL(n,2), \
                              n * 2 )

edit: So what I am really after is some way to check if something is a constant available at compile time, and hence a good argument for the BOOST_PP_ functions. I realize that this is different from what most people expect from a preprocessor and general programming recommendations. But there is no wrong way of programming, so please don't hate on the question if you disagree with its philosophy. There is a reason the BOOST_PP library exists, and this question is in the same spirit. It might just not be possible though.


Solution

  • You're trying to do something that is better left to the optimizations of the compiler.

    int main (void) {
      int b = 5;
      int a = b * 2;
    
      return a; // return it so we use a and it's not optimized away
    }
    

    gcc -O3 -s t.c

     .file "t.c"
     .text
     .p2align 4,,15
    .globl main
     .type main, @function
    main:
    .LFB0:
     .cfi_startproc
     movl $10, %eax
     ret
     .cfi_endproc
    .LFE0:
     .size main, .-main
     .ident "GCC: (Debian 4.5.0-6) 4.5.1 20100617 (prerelease)"
     .section .note.GNU-stack,"",@progbits
    

    Optimizing compiler will optimize.

    EDIT: I'm aware that you don't want to hear that the compiler "should" or "usually" does that. However, what you are trying to do is not something that is meant to be done in the C preprocessor; the people who designed the C language and the C preprocessor designed it to work with the preprocessing token as it's basic atom. The CPP is, in many ways, "dumb". This is not a bad thing (in fact, this is in many cases what makes it so useful), but at the end of the day, it is a preprocessor. It preprocesses source files before they are parsed. It preprocesses source files before semantic analysis occurs. It preprocesses source files before the validity of a given source file is checked. I understand that you do not want to hear that this is something that the parser and semantic analyzer should handle or usually does. However, this is the reality of the situation. If you want to design code that is incredibly small, then you should rely on your compiler to do it's job instead of trying to create preprocessor constructs to do the work. Think of it this way: thousands of hours of work went into your compiler, so try to reuse as much of that work as possible!