Search code examples
c

Compiler optimizations, divide macro expansions


I have following piece of code,

Scenario 1

/* get count of elements in an array */
#define COUNT(x)         sizeof(x)/sizeof(x[0])

struct Data data[] = {/* some data goes here */};

int count = COUNT(data);

Scenario 2

#define TOTAL            32
#define EACH              4
int count = (TOTAL/EACH)

I know macros are resolved during preprocessing and sizeof is a compile time operator, but what about the division: does it get optimised during compilation ?

Is there any tool to see the optimizations done by the compiler ?


Solution

  • Usually you can let the compiler show you the generated assembly code. With Visual C++ you can do that with the /Fa<file> option. gcc has the -S option.

    As for your question: Most compilers should precompute constant expressions, at least at optimisation levels higher than O0.

    Let's see with your example scenarios:

    #define COUNT(x)         sizeof(x)/sizeof(x[0])
    int data[] = {1, 2, 3, 4, 5};
    int count = COUNT(data);
    

    Compiled with cl /c /Fascenario1.asm scenario1.c yields:

    ...
    PUBLIC  _data
    PUBLIC  _count
    _DATA   SEGMENT
    _data   DD  01H
        DD  02H
        DD  03H
        DD  04H
        DD  05H
    _count  DD  05H
    _DATA   ENDS
    END
    

    You see the value for count close to the end, and it's indeed 5. So the compiler computed the value even with no optimisation turned on.

    Your second scenario:

    #define TOTAL            32
    #define EACH              4
    int count = (TOTAL/EACH);
    

    yields

    ...
    PUBLIC  _count
    _DATA   SEGMENT
    _count  DD  08H
    _DATA   ENDS
    END
    

    where the expression was precomputed as well.

    It's not uncommon at higher optimisation levels for the compiler to even evalute more complex expressions when you pass compile-time constants. As an example, I once looked at the code of three different ways of swapping two integers and once I turned optimisation on the compiler simply threw out the call to the swap method entirely, replacing the arguments to my test printf with the already-swapped values.