

C 言語では次の様にして`char`配列を初期化できますが、

[code]

    int main(void)
    {
        char str[] = "abc";
        ...
    }
    
[/code]

これは C99 の規格文書で 6.7.8 Initialization の paragraph 14

> An array of character type may be initialized by a character string literal,
> optionally enclosed in braces. Successive characters of the character string
> literal (including the terminating null character if there is room or if the
> array is of unknown size) initialize the elements of the array.

に基づくものです。一方 6.4.5 String literals の paragraph 5 には

> (...) The multibyte character sequence is then used to initialize an array
> of static storage duration and length just sufficient to contain the
> sequence. (...)

とあるのですが、この規定は文字列リテラルが初期化に使われる場合にも適用されるのでしょうか。

つまり、厳密に規格準拠のコンパイラは冒頭のコードをコンパイルする場合、`"abc"`を静的領域に確保してから`str`の初期化を行わなければならないのでしょうか？

冒頭の様なコードを gcc -std=c99 -O0 -S すると、当該部分は

[code]

        movl    $6513249, 24(%esp)
    
[/code]

となるので即値（6513249 = 0x636261）で初期化しており、6.4.5 の規定にそぐわない様に思われるのですが……。


CC BY-SA 3.0
2016-01-30T14:50:01.747
21511
2016-01-30T18:27:53.907
14190
question
c
C99 での文字列リテラルによる初期化について


C99 6.4.5 p5 には、文字列リテラルが静的記憶期間を持つ領域を初期化するのに使われるとの規定がありますが、いつ初期化されるかは定められていません。  
つまり、そのリテラルが出現した時に静的領域を初期化する必要はありません。例えば、ELF
形式では、プログラムのロード時、プログラムがメモリに展開される際に行われるようになっていると思います。  
また、配列変数の初期化についても、その静的領域を参照しなければならない旨はどこにも記述されていません。

そこで、今回のコードについては、以下のように解釈できます。

  1. `"abc"` は、6.4.5 p5 の規定に従い、`'a'`、`'b'`、`'c'`、`'\0'` からなる `char[4]` 型のリテラルとして解釈される。そして、質問文に引用されている部分の規定により、このリテラルは静的記憶期間を持つ領域をこれで初期化することになる。
  2. `char str[] = "abc"` は、1 で書いた通リの値を持つので、 6.7.8 p14 の規定通り、 `str` が長さ4で、各要素の値が `'a'`、`'b'`、`'c'`、`'\0'` となるように初期化される。この実行において、 **1で確保された静的記憶領域を全く参照する必要はない** ため、定数で一気に初期化を行った。
  3. さらに、1 で静的記憶期間を持つとしたものの、それがどこからも参照されていない。そのため、最適化としてそのような領域は削られることになった。

3 については、 gcc で最適化を無効にしても削られているので不審に思われるかもしれませんが、実のところこういったことはままあります。  
例えば、何もしない文 `"def";` などというものを関数内の適当なところに置いたところで、`"def"` に相当する領域はどこにも確保されません。  
文字列から離れてみれば、定数10で割る演算は、除算命令に頼らない方法に展開されます。  
こういったものは非常に基本的な部分に組込まれていて、最適化を無効化しても適用されるようになっているのだと思います。


CC BY-SA 3.0
2016-01-30T16:28:13.407
21513
2016-01-30T17:13:23.263
2016-01-30T17:13:23.263
7831
7831
21511
answer


[clang](http://clang.llvm.org/) の場合は gcc とは異なる様です。

[code]

    $ clang --version
    Ubuntu clang version 3.7.1-1ubuntu3 (tags/RELEASE_371/final) (based on LLVM 3.7.1)
    Target: x86_64-pc-linux-gnu
    
    $ clang -std=c99 -O0 -S a.c
    
      movl    .Lmain.str, %eax
           :
    
      .section  .rodata.str1.1,"aMS",@progbits,1
      .Lmain.str:
          .asciz  "abc"
          .size   .Lmain.str, 4
    
    $ clang -std=c99 -O0 a.c
    $ objdump -s -j .rodata a.out
    # or
    $ readelf -x .rodata a.out
    
    4005a0 01000200 61626300 25730a00           ....abc.%s..    
    
[/code]

文字列リテラルが rodata(Read Only DATA) section に置かれています。

本題とは関係のない事ですが、gcc の `-O0` オプションについて、実は全ての最適化が抑制されるわけではありません。

[code]

    $ gcc -Q --help=optimizers -O0
                 :
      -faggressive-loop-optimizations       [enabled]
      -falign-functions                     [disabled]
                 :
      -fasynchronous-unwind-tables          [enabled]
      -fauto-inc-dec                        [enabled]
                 :
    
[/code]


CC BY-SA 3.0
2016-01-30T18:04:23.737
21516
2016-01-30T18:27:53.907
2016-01-30T18:27:53.907
21511
answer