2016-11-04 3 views
2

constexprpreprocessor macroを使用して整数と文字列リテラルを定義することの違いを理解しようとしています。文字列リテラルと整数のC++ constexprとマクロ

アセンブリコードを検査するには 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を持っている機能の両方で観察することができ、次のアセンブリ出力を提供します

#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); 
} 

。私。リテラルとconstexp intマクロ整数の間にフードの下目に見える違いは、存在しないconstexpr intは、一方別のセクション_ZL10second_int

に格納されていても、文字列リテラルのために、我々は、命令movl $_ZL13second_string, %edimovl $.LC0, %ediマップがわかりそれぞれの文字列リテラルを2つの異なるセクションに分割します。

これら2つのセクションの違いは何ですか?実行可能ファイルが読み込まれると、メインメモリの別の部分にマップされますか?はいの場合、他の部分よりもアクセスが速いのですか?私はパフォーマンスのインパクトをプロファイルできますが、これらの2つのセクションの理論的な理由と違いを理解したいと思います。

+1

で、同じです実行可能な領域が無駄になります。 '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のは、あなたが二回文字列 `#のdefine`を使用する場合は、重複除外するために文字列リテラルをコンパイラに依存しなければならない、より良い選択

関連する問題