我的基本情况:我有一个类似#define foo (Flag1 | Flags2 | Flag3)
的包含文件,所以它是一个预定义的位标志组合。为了类型安全,我想用静态consts替换这些#defines,即static const int foo = (Flag1 | Flag2 | Flag3)
(或类似的)。这个包含文件包含在程序的许多地方。
现在当我在启用所有相关优化选项的版本构建时(使用VS2010的C ++编译器),替换#defines似乎会将可执行文件增加几个KiB,具体取决于我替换了多少常量。 / p>
为什么会这样?据我所知,整数常量应该被“内联”到尽可能产生的ASM代码中,我不知道使用static const
vs #define
如何在这里产生影响。显然,变量没有内联,因为反汇编显示:
#define:
01325041 or eax,0FFD87FE0h
static int:
011E5451 or eax,dword ptr [CMainFrame::s_TemplateModulePaths+38h (151F008h)]
所以最后一个问题是:我如何避免#define
,但仍然依赖于直接插入到生成的程序集中的变量?
答案 0 :(得分:3)
没有理由编译器无法消除静态const变量。如果你正在编译并启用了优化,我很惊讶VC ++没有这样做。
我尝试用gcc编译这段代码。
enum { FLAG1 = 1 << 0, FLAG2 = 1 << 1, FLAG3 = 1 << 2 };
static const int foo = (FLAG1 | FLAG2 | FLAG3);
int main(){
return foo;
}
关闭优化后,它会内联值但仍保留变量的存储空间。
_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
在O2,它内联了值并摆脱了存储空间。
_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
我唯一的想法是,不正确的编译器设置或VC ++未能进行此优化,Flags变量可能不是编译时常量,这意味着必须在程序启动时计算表达式的值,这会阻止内联。
答案 1 :(得分:0)
如评论中所示,类型安全运算符|我的枚举重载似乎阻止VC ++内联ORed值。我想我将继续使用#define
版本,因为我讨厌增加可执行文件大小,如果没有任何好处(不,这不是过早的优化) - 毕竟,它不会增加可读性,并且因为它的组合标志已经是我的flagset枚举类型,我猜也不会失去任何类型安全性。
答案 2 :(得分:0)
#define ERROR_1 int(1)
#define ERROR_2 int(2)
等...
然后,您将直接在指令中获得值,并且您还将进行类型检查:)并且没有任何优化参数。
在我看来,static const int BLABLA=1;
的东西只是在某些常量中添加命名空间......并且在代码中使用更多的ram和ram访问权限,当{{1}的符号时,这真的没有意义常量必须是唯一的,并且当对内存中的错误代码的引用不一致(任何恶意软件/错误可以在运行时在ram中修改这些值)而不是此错误代码的直接值时,直接在指令中。
但它更多的是关于现代编程政治...有些人声称,使用#define
,而其他人(比如我和微软)更喜欢更简单的版本public static const int
。
答案 3 :(得分:-2)
您可以从另一个角度查看问题来解决您的问题:您可以将数据和使用它的函数放在一起。
在OO语言中,这意味着使常量foo
成为类的私有静态属性。该类应该具有使用foo
的所有函数作为公共方法。
作为静态私有属性,它将在.cpp文件中定义,并且在可执行文件中只有一个实例。
我理解这将是您的代码中的一个重大变化,而不是简单的重构:当然,这并不像将foo
的定义从#define
修改为静态全局常量那么简单。但保持使用它们的数据和方法紧密相连(即:在同一类中)将为您带来许多非功能性优势。
答案 4 :(得分:-2)
我的猜测是你在头文件中有static const int foo = (Flag1 | Flag2 | Flag3)
。这会导致常量的版本分别存储在每个目标文件中。 #define嵌入了文字,它们都是通过合并来组合的。
试试这个,在一个C ++文件中有const int foo = (Flag1 | Flag2 | Flag3)
,然后在标题中有extern const int foo
。
<强>更新强>
很抱歉,如果我的回答不符合您的要求。我解决了静态const变量的文件大小问题。
我想这就是你想要的一切。除非一段代码导致性能问题,否则我永远不会担心这种优化内联。对我来说,类型安全和文件大小是我重视CPU优化的东西。此外,extern const允许通过覆盖率和计时工具进行更好的分析。
过早优化是编程中所有邪恶(或至少大部分)的根源。