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
なぜ?
別の興味深いこと:int、char、stringが公開されている場合、出力は
... int : something
... char :
... string : something_2
something_2 - something
は常に8に等しいなぜ?(9ではない)
Bのアドレスを取得すると、_char *
_を取得します。 _operator<<
_はそれをC文字列として解釈し、アドレスの代わりに文字シーケンスを出力しようとします。
代わりにcout << "address of char :" << (void *) &b << endl
を試してください。
[編集] Tomekがコメントしたように、この場合に使用するより適切なキャストは_static_cast
_であり、これはより安全な代替手段です。これは、Cスタイルのキャストの代わりにそれを使用するバージョンです。
_cout << "address of char :" << static_cast<void *>(&b) << endl;
_
2つの質問があります。
ポインターを印刷すると、int*
およびstring*
のアドレスが印刷されますが、char*
には特別なオーバーロードがあるため、operator<<
の内容は印刷されません。アドレスが必要な場合は、次を使用してください:static_cast<const void *>(&c);
int
とstring
のアドレスの違いが8
である理由お使いのプラットフォームでは、sizeof(int)
は4
であり、sizeof(char)
は1
であるため、8
ではなく5
ではない理由を実際に確認する必要があります。その理由は、文字列が4バイト境界に配置されるためです。マシンはバイトではなく単語で動作し、したがって単語がここで数バイトとそこで数バイト「分割」されていない場合はより高速に動作します。これはalignmentと呼ばれます
システムはおそらく4バイト境界に合わせます。 64ビット整数の64ビットシステムの場合、差は16になります。
(注:64ビットシステムは、通常、intではなくポインターのサイズを参照します。したがって、4バイトのintを持つ64ビットシステムは、4 + 1 = 5であるにもかかわらず、8に切り上げます。 。sizeof(int)が8の場合、8 + 1 = 9ですが、これは16に切り上げられます)
Charのアドレスをostreamにストリームすると、それはそれをASCIIZ "Cスタイル"文字列の最初の文字のアドレスとして解釈し、推定された文字列を出力しようとします。 NULターミネーターがないため、出力がメモリからの読み取りを試行するか、OSがシャットダウンして無効なアドレスから読み取ろうとするまで、メモリからの読み取りを試み続けます。スキャンしたゴミはすべて出力に送られます。
おそらく、(void*)&b
のように、キャストすることで、必要なアドレスを表示できます。
構造体へのオフセットについて:文字列がオフセット8に配置されていることを確認しました。これは、おそらく32ビットの整数、次に8ビットの文字があるためです。その後、コンパイラーがさらに3つの8ビットの文字を挿入して、文字列オブジェクトは、32ビットのワード境界に配置されます。多くのCPU /メモリアーキテクチャでは、効率的な操作を実行するために、ポインタ、intなどをWordサイズの境界に置く必要があります。そうでない場合、値を使用する前に、メモリから複数の値を読み取って組み合わせるために、さらに多くの操作を行う必要があります。手術中。システムによっては、すべてのクラスオブジェクトがWordの境界で開始する必要がある場合と、特にstd::string
がsize_t、ポインタ、またはそのような配置を必要とするその他の型で開始する場合があります。
char*
をstd::ostream
に渡すと、ポイントするCスタイル(つまり、char配列、char*
)の文字列が出力されるためです。
"hello"
はchar*
であることを忘れないでください。
Charのアドレスは、nulで終了する文字列として扱われ、そのアドレスの内容を表示しています。これはおそらく未定義ですが、この場合は空の文字列です。ポインタをvoid *
にキャストすると、希望する結果が得られます。
何か2と何か8の違いは、変数が宣言されているスタック内の場所をコンパイラが自分で決定できるように調整および機能されているためです。
2番目の問題については、コンパイラーはデフォルトで構造体メンバーを埋め込みます。デフォルトのパッドはsizeof(int)
に4バイトです(ほとんどのアーキテクチャ)。これが、int
の後にchar
が続く構造では8バイトを使用するため、string
メンバーはオフセット8にあります。
埋め込みを無効にするには、#pragma pack(x)
を使用します。ここで、xは埋め込みサイズ(バイト単位)です。
構文は
cout << (void*) &b
空白の理由はhrntが正しい:_&b
_には_char*
_型があるため、最初のゼロバイトまで文字列として出力されます。おそらくb
は0です。b
をたとえば「A」に設定した場合、印刷出力は「A」で始まり、次のゼロまでガベージが続く文字列であることが期待されます。バイト。 static_cast<void*>(&b)
を使用して、アドレスとして出力します。
2番目の質問の場合、_&c - &i
_は8です。これは、intのサイズが4、charが1で、文字列が次の8バイト境界から始まるためです(おそらく64ビットシステムです)。各型には特定の配置があり、C++はそれに従って構造体のフィールドを配置し、適切にパディングを追加します。 (経験則では、サイズNのプリミティブフィールドはNの倍数に揃えられます。)特に、アドレスに影響を与えずに、char
の後に3つのb
フィールドを追加できます_&c
_。