9

Linux x86_64マシンで、GCCによってコンパイルされた次のCプログラムをコンパイルして実行すると、次のようになります。

#include <stdio.h>

int main(void)
{
    char *p1 = "hello";               // Pointers to strings
    char *p2 = "hello";               // Pointers to strings
    if (p1 == p2) {                   // They are equal
    printf("equal %p %p\n", p1, p2);  // equal 0x40064c 0x40064c
                                      // This is always the output on my machine
    }
    else {
    printf("NotEqual %p %p\n", p1, p2);
    }
}

私は常に次のように出力を取得します:

等しい0x40064c0x40064c

文字列は定数テーブルに格納されていることは理解していますが、動的に割り当てられたメモリと比較すると、アドレスが低すぎます。

次のプログラムと比較してください。

#include <stdio.h>

int main(void)
{
    char p1[] = "hello";                // char arrar
    char p2[] = "hello";                // char array
    if (p1 == p2) {
    printf("equal %p %p\n", p1, p2);
    }
    else {                              // Never equal
    printf("NotEqual %p %p\n", p1, p2); // NotEqual 0x7fff4b25f720 0x7fff4b25f710
                                        // Different pointers every time
                                        // Pointer values too large
    }
}

これらは独立して操作できる2つの配列であるため、2つのポインターは等しくありません。

GCCがこれら2つのプログラムのコードを生成する方法と、実行中にそれらがメモリにどのようにマップされるかを知りたいです。これはすでに文書化されているので、何度も文書化することを歓迎します。

4

1 に答える 1

13

どちらの場合も、コンパイラは文字列の実際のバイトをプログラムのセクションで"hello"1 回だけ出力します ( rodataread only dataを表します)。.rodata

これらは、実際には実行可能ファイルからメモリに直接マップされ、コード セクションと多少似ています。そのため、動的に割り当てられたものとはかけ離れています。

それで:

char *p = "hello";

pこの (読み取り専用) データのアドレスに初期化するだけです。そして明らかに:

char *q = "hello";

まったく同じアドレスを取得します。これは文字列プーリングと呼ばれ、コンパイラのオプションの一般的な最適化です。

しかし、あなたが書くとき:

char p[] = "hello";

おそらく次のようなものが生成されます。

char p[6];
memcpy(p, "hello", 6);

実際"hello"には、読み取り専用のプールされた文字列のアドレスです。

への呼び出しmemcpyは、説明のみを目的としています。関数呼び出しを使用する代わりに、インラインでコピーすることをお勧めします。

後で行う場合:

char q[] = "hello";

別の配列と別の を定義しますmemcpy()。同じデータですが、アドレスが異なります。

しかし、これらの配列変数はどこに存在するのでしょうか? まあ、それは依存します。

  • それらがローカルで静的でない変数の場合: スタック内。
  • それらがグローバル変数の場合: それらは.data実行可能ファイルのセクションにあり、正しい文字が既にそこにある状態でそこに保存されるmemcpyため、実行時に何も必要ありません。memcpyの前に実行する必要があるため、これは素晴らしいことですmain
  • ローカル静的変数の場合: グローバル変数の場合とまったく同じです。両方とも一緒に呼ばれるvariables of static durationか、そのようなものです。

ドキュメントのリンクについては、申し訳ありませんが、私は何も知りません。

しかし、自分で実験を行うことができる場合、誰がドキュメントを必要とするでしょうか? そのための最適なツールはobjdump、プログラムを逆アセンブルし、データ セクションをダンプするなどの機能を備えた です。

これがあなたの質問に答えてくれることを願っています...

于 2012-09-12T18:15:37.347 に答える