- 基本的に、ポインターはメモリアドレスを格納するために使用される変数であり、常に
16進数(メモリアドレス)であるのに、アドレスを格納するために異なるデータ型が必要なのはなぜですか。 - 例:int *a; これを float アドレスの格納に使用できますか。
5 に答える
すべてのポインターが同じサイズである必要はありません。10 MB に揃える必要がある大きな構造体がある場合、コンパイラは、変数が配置される可能性のあるすべてのアドレスを格納するために (通常の 32 または 64 ではなく) 8 ビットしか必要ないと判断する可能性があります。
また、別のデータ型も必要ありません。問題なく使用できますvoid*
が、なぜそうするのでしょうか? C++ では、これはコード臭です。
タイプセーフもあります。int*
あなたは が を指していることを知ってint
おり、これはあなたにとって有利です。
まず、ポインターが 16 進数で格納されているマシンを知りません。私がよく知っているすべてのマシンは、内部でバイナリ表現を使用していました。(少なくとも過去 30 年または 40 年間、IIRC、IBM 1401 はあらゆる場所で 10 進数を使用していました。)
他の人が指摘したように、すべてのポインターが同じサイズと表現を持つわけではありません。私はchar*
、他のデータ ポインター型よりも大きいマシンで作業してきました。もちろん、関数ポインターとデータ ポインターのサイズが異なることは非常に一般的でした。
ただし、本当の答えは、C および C++ の型システムに基づいています。p
がポインターの場合、 の型は*p
何ですか? のようなものを書く場合*p + *q
、コンパイラは整数演算と浮動小数点演算のどちらを使用するかを知る必要があります。
reinterpret_cast
2 番目の質問については、通常、はい、おそらくどこかに が必要になるでしょう。ただし、 your で合法的にできる唯一のことは、それを;int*
にキャストすることです。float*
逆参照は未定義の動作です。
とにはいくつかの例外がchar*
ありunsigned char*
ます。そして実際には、自分が何をしているのかを知っていれば、次のようなことを回避できます。
float f;
int* a = reinterpret_cast<int*>( &f );
std::cout << *a << std::endl;
私は実際に、ある種の低レベルのデバッグまたはプログラミングに対して同様のことを行っています。から指数フィールドを抽出するようなものfloat
。ただし、このようなコードは非常にまれであり、正式には未定義の動作を伴うため、コンパイラが実際に何を行うかを確認し、場合によっては特定の最適化を無効にする必要があります。
ポインターが指すデータを解釈する方法に関する情報を提供するためです。
例:int *a; これを float アドレスの格納に使用できますか。
C 型の安全でない機能を介して: はい、ただし直接ではありません。特に最近のコンパイラと標準 (より安全である傾向があります) ではそうです。
アドレスを格納するために異なるデータ型が必要なのはなぜですか
それは実際には正しい質問であり、答えはその中に隠されています - なぜアドレスを格納するために別のデータ型が必要なのですか? 私たち(プログラマー)はそれを必要としています。マシンは気にしません - 1 つの数値が他の数値とまったく同じです。
「変数」を一部のデータの「プレースホルダー」と考えると、プログラミング言語では、データ自体の使用と変数の使用の間に二分法があります。データだけが必要な場合 (印刷する必要がある場合など) もあれば、このデータが保存されているアドレスが必要な場合もあります (変更できるようにするためなど)。ほとんどの言語には、これら 2 つのケースを混同するシンタックス シュガーがあり、コンテキストごとに変数識別子の扱いが異なります。
そのようなケースの 1 つが次のようになります。
a = 1;
この場合、コンパイラは「a」で識別される変数のアドレスを検索し、このアドレスに「1」を書き込みます。識別子 "a" はポインタでもかまいません。次に、別のことを見てください。
if (a == 1) ... ;
「a」で識別される変数のアドレスを何かと比較しているのではなく、このアドレスに格納されているものを「1」と比較しています。
プログラマーの利便性のために、さまざまな「ポインター型」が再び存在します。これは基本的に、データに誤ってアクセスしてバグを減らすためです。この例を見てください:
double d;
double* dp;
int i;
int* ip;
デフォルトでは、Cはそれについて非常にリラックスしており、通常は次のことができます:
dp = ip;
また
dp = &i;
... しかし!sizeof(i)==4 および sizeof(d)==8 であるため、dp ポインターを逆参照すると、4 しか保持しない変数 (i) から 8 バイトを読み取ろうとすることになります。これは、予測できない 4 を読み取っていることを意味します。 i の最初の 4 バイトの後の (ランダムな) バイト。これは絶対にやりたくないことです。
繰り返しますが、これはすべて私たちの便宜のためです。機械は関係ありません。両方のポインターは、CPU に対してまったく同じように見え、まったく同じように動作します。