字符串文字与整数中的C ++ constexpr vs宏
Posted
技术标签:
【中文标题】字符串文字与整数中的C ++ constexpr vs宏【英文标题】:C++ constexpr vs macro in string literal vs integer 【发布时间】:2016-11-04 08:24:54 【问题描述】:我正试图找出使用constexpr
和preprocessor macro
定义整数和字符串字面量之间的“幕后”区别。
#define FIRST_STRING "first_stringer"
constexpr char second_string[] = "second_stringer";
#define FIRST_INT 1234
constexpr int second_int = 12345;
int main ()
printf("%s\n", second_string);
printf("%s\n", FIRST_STRING);
printf("%d\n", FIRST_INT);
printf("%d\n", second_int);
return 0;
void hello()
printf("%s\n", second_string);
printf("%s\n", FIRST_STRING);
printf("%d\n", FIRST_INT);
printf("%d\n", second_int);
使用g++ -S main.cpp -std=c++11
编译时会给出以下汇编输出
.file "main.cpp"
.section .rodata
.LC0:
.string "first_stringer"
.LC1:
.string "%d\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $_ZL13second_string, %edi
call puts
movl $.LC0, %edi
call puts
movl $1234, %esi
movl $.LC1, %edi
movl $0, %eax
call printf
movl $12345, %esi
movl $.LC1, %edi
movl $0, %eax
call printf
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.globl _Z5hellov
.type _Z5hellov, @function
_Z5hellov:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $_ZL13second_string, %edi
call puts
movl $.LC0, %edi
call puts
movl $1234, %esi
movl $.LC1, %edi
movl $0, %eax
call printf
movl $12345, %esi
movl $.LC1, %edi
movl $0, %eax
call printf
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size _Z5hellov, .-_Z5hellov
.section .rodata
.align 16
.type _ZL13second_string, @object
.size _ZL13second_string, 16
_ZL13second_string:
.string "second_stringer"
.align 4
.type _ZL10second_int, @object
.size _ZL10second_int, 4
_ZL10second_int:
.long 12345
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",@progbits
在检查汇编代码时,我们可以观察到在两个函数中我们都有指令movl $1234, %esi
和movl $12345, %esi
。 IE。宏整数文字和constexp int
之间没有明显的区别,即使constexpr int
存储在单独的部分_ZL10second_int
中
另一方面,对于字符串文字,我们看到指令movl $_ZL13second_string, %edi
和movl $.LC0, %edi
将它们各自的字符串文字映射到两个不同的部分。
这两个部分有什么区别?加载可执行文件后,它们是否映射到主内存的不同部分?如果是,访问某个部分是否比另一部分更快?我知道我可以分析性能影响,但我想了解这两个部分之间的理论原因和区别。
【问题讨论】:
如果两次使用字符串#define
,则必须依赖编译器对字符串文字进行去重,否则会浪费可执行空间。 constexpr
保证唯一性。
【参考方案1】:
这些在功能上是等效的。请注意,两种情况下的实际数据都是使用.string
指令声明的。唯一的区别在于标签名称,其中实际上是 C++ 对象 (second_string
) 的名称有一个错误名称,而宏只有一个通用标签名称。
如果您在 Linux 中的可执行文件上运行 objdump
,您会注意到两个字符串都存储在 .rodata
部分中:
String dump of section '.rodata':
[ 4] %s^J
[ 8] first_stringer
[ 17] %d^J
[ 20] second_stringer
【讨论】:
【参考方案2】:一个原因是宏由预处理器处理,而 constexpr 由编译器处理。所以 constexpr 不仅仅是一个字符串替换,它还检查类型,例如。
所以即使汇编是一样的,在我看来,constexpr 是一个更好的选择
【讨论】:
以上是关于字符串文字与整数中的C ++ constexpr vs宏的主要内容,如果未能解决你的问题,请参考以下文章