64
class Address {
      int i ;
      char b;
      string c;
      public:
           void showMap ( void ) ;
};

void Address :: showMap ( void ) {
            cout << "address of int    :" << &i << endl ;
            cout << "address of char   :" << &b << endl ;
            cout << "address of string :" << &c << endl ;
}

出力は次のとおりです。

         address of int    :  something
         address of char   :     // nothing, blank area, that is nothing displayed
         address of string :  something 

なんで?

もう 1 つの興味深い点: int、char、string が公開されている場合、出力は次のようになります。

  ... int    :  something 
  ... char   :   
  ... string :  something_2

something_2 - somethingは常に 8です。なぜですか? (9 ではない)

4

8 に答える 8

99

b のアドレスを取得すると、 が得られchar *ます。operator<<はそれを C 文字列として解釈し、そのアドレスの代わりに文字シーケンスを出力しようとします。

cout << "address of char :" << (void *) &b << endl代わりに試してください。

[編集] Tomek がコメントしたように、この場合に使用するより適切なキャストstatic_castは、より安全な代替手段です。C スタイルのキャストの代わりにそれを使用するバージョンを次に示します。

cout << "address of char   :" << static_cast<void *>(&b) << endl;
于 2011-02-01T09:21:42.263 に答える
31

2 つの質問があります。

  • 文字のアドレスを出力しない理由:

ポインターを出力すると、int*とのアドレスが出力されますが、 には特別なオーバーロードがあるstring*ため、 の内容は出力されません。アドレスが必要な場合は、次を使用します。char*operator<<static_cast<const void *>(&c);

  • intとの住所stringが異なる理由8

あなたのプラットフォームsizeof(int)には4ありsizeof(char)ます1ので、なぜそうし8ないのかを本当に尋ねるべき5です。その理由は、文字列が 4 バイト境界でアラインされているためです。マシンはバイトではなく単語で動作するため、単語がここで数バイトとあちらで数バイトに「分割」されていない場合は、より高速に動作します。これをアライメントといいます

お使いのシステムは、おそらく 4 バイト境界に位置合わせされています。64 ビット整数を使用する 64 ビット システムの場合、差は 16 になります。

(注: 64 ビット システムは一般に、int ではなくポインターのサイズを参照します。したがって、4 バイトの int を使用する 64 ビット システムでも、4+1 = 5 として 8 の差がありますが、8 に切り上げられます。 . sizeof(int) が 8 の場合、8+1 = 9 ですが、これは 16 に切り上げられます)

于 2011-02-07T17:04:41.750 に答える
14

char のアドレスを ostream にストリーミングすると、ostream はそれを ASCIIZ "C スタイル" 文字列の最初の文字のアドレスであると解釈し、推定された文字列を出力しようとします。NUL ターミネータがないため、出力はメモリからの読み取りを試行し続けるか、OS が無効なアドレスからの読み取りを試みるためにシャットダウンするまで、メモリからの読み取りが試行されます。スキャンするゴミはすべて出力に送信されます。

のようにキャストすることで、必要なアドレスを表示させることができます(void*)&b

構造体へのオフセットについて: 文字列がオフセット 8 に配置されていることを確認しました。文字列オブジェクトは 32 ビット ワード境界に配置されます。多くの CPU/メモリ アーキテクチャでは、ポインタや int などをワード サイズの境界上に配置して効率的な操作を実行する必要があります。そうしないと、値を使用できるようになる前に、メモリから複数の値を読み取って結合するために、さらに多くの操作を実行する必要があります。操作で。システムによっては、すべてのクラス オブジェクトがワード境界で開始する必要がある場合やstd::string、特に size_t、ポインター、またはそのようなアラインメントが必要なその他の型で開始する場合があります。

于 2011-02-01T09:22:07.763 に答える
11

char*aをに渡すと、それが指すstd::ostreamC スタイル (つまり、char 配列、 ) 文字列が出力されるためです。char*

"hello"であることを忘れないでくださいchar*

于 2011-02-01T09:21:33.577 に答える
4

char のアドレスはヌル終了文字列として扱われ、そのアドレスの内容を表示しています。これはおそらく未定義ですが、この場合は空の文字列です。ポインタを にキャストするとvoid *、希望する結果が得られます。

something2 と something 8 の違いは、変数がスタック内のどこで宣言されているかをコンパイラが独自に決定できるためです。

于 2011-02-01T09:23:31.480 に答える
2

2 番目の問題については、コンパイラはデフォルトで構造体メンバーをパディングします。デフォルトのパッドはsizeof(int), 4 バイトです (ほとんどのアーキテクチャで)。これが、構造体で a のint後に acharが 8 バイトかかるため、stringメンバーはオフセット 8 にあります。

パディングを無効にするには、 を使用#pragma pack(x)します。ここで、x はパディング サイズ (バイト単位) です。

于 2011-02-01T09:25:24.100 に答える
2

あなたの構文は

cout << (void*) &b
于 2011-02-01T10:24:44.217 に答える
0

hrnt は空白の理由について正しいです: &bhas typechar*であるため、最初のゼロバイトまで文字列として出力されます。おそらくb0 ですb。たとえば、'A' に設定した場合、出力は 'A' で始まり、次の 0 バイトまでゴミが続く文字列であると想定する必要があります。static_cast<void*>(&b)住所として印刷する場合に使用します。

2 番目の質問&c - &iは 8 です。これは、int のサイズが 4、char が 1、文字列が次の 8 バイト境界から始まるためです (おそらく 64 ビット システムを使用しているはずです)。各型には特定の位置合わせがあり、C++ はそれに従って構造体のフィールドを位置合わせし、適切にパディングを追加します。(経験則では、サイズ N のプリミティブ フィールドは N の倍数に揃えられます。) 特に、アドレスに影響を与えずに、charあとに 3 つのフィールドを追加できます。b&c

于 2011-02-13T20:31:27.330 に答える