2016-11-04 69 views
2

我想弄清楚使用constexprpreprocessor macro定義整數和字符串文字之間的「底層」差異。C++ constexpr vs宏中的字符串字面值與整數

#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, %esimovl $12345, %esi。即有一個宏觀整數文字和constexp int之間的引擎蓋下沒有明顯的區別,即使constexpr int被儲存在一個單獨的部分_ZL10second_int

在另一方面,對於字符串常量,我們看到,該指令movl $_ZL13second_string, %edimovl $.LC0, %edi地圖他們各自的字符串文字到兩個不同的部分

這兩個部分有什麼區別?一旦加載可執行文件,它們是否映射到主內存的不同部分?如果是的話,訪問比另一部分快嗎?我知道我可以描述性能影響,但我想了解這兩部分之間的理論原因和差異。

+1

如果使用字符串'#define'兩次,你必須依靠編譯器來刪除重複的字符串文字,或可執行空間被浪費。 'constexpr'保證獨特性。 –

回答

3

這些在功能上是等同的。請注意,兩種情況下的實際數據均使用.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是一個更好的選擇