Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

static const vs. #define in c++ - differences in executable size

Tags:

c++

constants

My basic situation: I have an include file that has something like #define foo (Flag1 | Flags2 | Flag3), so it's a predefined combination of bit flags. For the sake of type-safety, I wanted to replace these #defines by static consts, i.e. static const int foo = (Flag1 | Flag2 | Flag3) (or similar). This include file is included in dozens of places in the program.

Now when I'm doing a release build with all relevant optimisation options enabled (using the C++ compiler of VS2010), replacing the #defines seems to increase the executable by a few KiB, depending on how many constants I replaced.

Why does this happen? To my knowledge, integer constants are supposed to be "inlined" into the ASM code that is produced if possible, and I don't see how using a static const vs #define would make a difference here. Clearly, the variable isn't inlined as the disassembly shows:

#define:
01325041  or          eax,0FFD87FE0h
static int:
011E5451  or          eax,dword ptr [CMainFrame::s_TemplateModulePaths+38h (151F008h)]

So the final question is: How can I avoid #define but still rely on the variable being inserted directly into the generated assembly?

like image 654
j_schultz Avatar asked Aug 02 '12 14:08

j_schultz


1 Answers

There is no reason the compiler couldn't eliminate the static const variable. If you're compiling with optimizations turned on, I'm surprised that VC++ doesn't do that.

I tried compiling this code with gcc.

enum { FLAG1 = 1 << 0, FLAG2 = 1 << 1, FLAG3 = 1 << 2 };

static const int foo = (FLAG1 | FLAG2 | FLAG3);

int main(){
    return foo;
}

With optimizations turned off, it inlined the value but still reserved storage space for the variable.

_main:
LFB0:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    call    ___main
    movl    $7, %eax  ;value inlined
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE0:
    .section .rdata,"dr"
    .align 4
__ZL3foo:                     ; storage space for foo
    .long   7

At O2 it inlined the value and got rid of the storage space.

_main:
LFB0:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
   .cfi_def_cfa_register 5
    andl    $-16, %esp
    call    ___main
    movl    $7, %eax    ; value inlined
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
   .cfi_endproc
LFE0:
; no storage space for foo

My only thought other that incorrect compiler settings, or VC++ failing to make this optimization, is that the Flags variables might not be compile-time constants which would mean that the value of the expression has to be computed at program start-up, which would prevent inlining.

like image 139
Dirk Holsopple Avatar answered Nov 09 '22 07:11

Dirk Holsopple