私はこのコードをインタビューで見つけました。「ptrをptrにptrを明示的にキャスト」
int main()
{
int **p;
p = (int **) new int(7);
cout<<*p;
return 0;
}
* pで実行時にエラーが発生する予定です。しかし、コードを実行すると、出力 "0x7"で正常に実行されました。誰かが私にこのことがどう働いているのか説明してください。ありがとう。
私はこのコードをインタビューで見つけました。「ptrをptrにptrを明示的にキャスト」
int main()
{
int **p;
p = (int **) new int(7);
cout<<*p;
return 0;
}
* pで実行時にエラーが発生する予定です。しかし、コードを実行すると、出力 "0x7"で正常に実行されました。誰かが私にこのことがどう働いているのか説明してください。ありがとう。
適切な答えはです。上記のうちのどれもには、特別な制約が与えられていない限り、ありません。基本的にコードはint
を割り当てて、そのメモリをint*
(reinterpret_cast
を介して)のように解釈しています。最初の問題はreinterpret_cast
され、結果は一般的なケースで不定で、int
のサイズは(64ビットのアーキテクチャを考える)int*
のサイズよりも小さい場合、あなたがそうであるように結果が未定義の動作である、ということですnew
呼び出しで割り当てられたサイズを超えて読み取ります。
int(32ビット)をint *(64ビット)にキャストすると、結果は64ビットに拡張されます。 – gulyan
@gulyanしかし、この場合、コンパイラはその種のキャストを行うべきであることを知らない。行われる唯一のキャストは、上の行のint *からint **です。 –
@gulyan:いいえ、32ビット整数から64ビット整数への 'static_cast'では、コンパイラはサイズを拡張して変換を行いますが、' reinterpret_cast'ではコードを*メモリを再解釈する*。つまり、 'int'へのポインタを取得し、次の64ビット(8バイト)を' int * 'のように読み込みます。これは未定義の動作です。これはCスタイルのキャストでの最大の問題の1つですが、明示的なC++キャストと同じくらい明確ではありません –
あなたは、ポインタ(例えばメモリアドレス7または0x07の)
int **p = (int**) new int(7);
にキャストよりも新しいint型を作成し、7
int *x = new int(7);
に値をあなたにそれを初期化次に、あなたは、このアドレスを表示coutと
*p is equal to (int*)7
これはその値7
であり、それへのポインタを返すint
にメモリを割り当て値7
これはコードが正しいことを示すか、少なくともコードはすべての状況で同じ出力を生成しますが、出力は生成されません。 'p'の逆参照は未定義の動作を引き起こします。 –
new int(7);
とポインタです。
int **p = (int **) new int(7);
int**
ように、そのメモリを解釈するようにコンパイラーに指示します。
cout << *p;
アドレス*p
でint *
と出力にその値であるコンパイラに指示します。値は0x07
です。 (アドレスとして7
を扱います)。余分な逆参照は、クラッシュ(正確には未定義の動作です)を招きます。
コードはすでに定義されていない動作です...追加の逆参照を実行する必要はありません。 –
@Luchian Grigore:ありがとうございます。 – CppLearner
int main()
{
int **p; // declare pointer to pointer called p
p = (int **) new int(7); // new allocates integer initialized to value of 7 and returns a pointer. Cast the pointer to a point to pointer. p now represents a pointer to a pointer with contents of 0x7. If you called **p you would get the contents at address 0x7.
cout << *p; // dereference p, this yields a pointer, which is an int of value 0x7.
}
この質問は、ポインタの知識をテストすることを目的としたものではありますが、あまり実用的ではありません。
int main()
{
int **p = (int **) new int(7);
cout << *p;
}
そこで、new int(7)
は、メモリのsizeof(int)
バイトを割り当てて、それへのポインタを返します。メモリがアドレスXにあるとしましょう。次に、Xは(int**)
にキャストされ、p
に格納されます。
*p
は、int*
としてアドレスX
でint
値7をintreprets意味し、int**
を間接参照します。常に未定義の動作を関係なく、データ・タイプおよび任意のreintrepretation -
sizeof(int*)
場合はint*
がnew
と割り当てられたバッファを超えて読み出されるように、次に読み出し、sizeof(int)
より大きい。
それは同じサイズである場合、CPUはint*
として整数7を含むメモリを読み取るしようとする - これは、典型的に値int*(7)
が得られるが、標準5.2.10.5見:
整数型または列挙型の値を明示的にポインタに変換することができます。* [脚注:整数定数式(expr.const)を値0で変換すると、常にNULLポインタ(conv.ptr)が生成されますが、他の式を値ゼロに変換すると、NULLポインタを返す必要はありません。 --- end foonote] 十分な大きさの整数に変換されたポインタ(実装上に存在する場合)と同じポインタ型に戻ったポインタは元の値を持ちます。ポインタと整数の間のマッピングは、そうでなければ実装定義されます。
したがって、整数値はポインタ値に変換されることが保証されています - 未定義ではありませんが、値は実装定義です。 「7」を出力する観測された振る舞いを説明 - それでも、可逆演算であることは、それは、int
7が値7でint*
が得られることを圧倒的にそうです。
int
サイズより小さい場合、それはint
値のスライスを読み取り、ポインタとしてそれを解釈します。エンディアンに応じて、スライスは0または7、または何か他のものでもよいが、int
として再び表示されるポインタ値に変換可能でなければならない。
あなたは何をしようとしていますか?大まかな基本的なルールは、キャストする必要がある場合は、間違っていることです。 'new int(7)'は 'int *'を返すので、キャストする必要があります。しかし、キャスティングはコードを正しいものにしません。あなたはそれが間違っているという事実の論文だけです。キャストを取り除いてそこから作業してください。 –
@David:コードはOPからではなく、インタビューによるものです。 – Vlad
@ David Heffernan:これは、筆記試験の面接問題です。 4つのオプションがコンパイル時エラー、実行時エラー、コードが正常に実行され、上記のどれも実行されませんでした。そのようなインタビューの質問でどのような知識を試そうとしているのか分かりません。 – CppLearner