逆方向の作業:
e ++;
cout << e << " " << endl;
これが 0 を出力する場合、e
このコードを実行する前の の値は であったに違いありません-1
。
int e = &d - c;
したがって、上記のアドレス減算の結果は-1
.
unsigned int a /* = whatever, the value of a doesn't matter */;
unsigned int &b = a;
unsigned int *c = &b;
unsigned int d /* = whatever, the value of d doesn't matter */;
b
は への参照a
であるため、&b
と同等&a
です。
So&d - c
は と等価&d - &a
であり、その減算は になります-1
。
結論: のアドレスは のアドレスd
のsizeof (unsigned int)
バイト後ですa
。(ポインター減算は、ポイント先の型のサイズによってスケーリングされます。)
おそらく。
実際、独立して定義された 2 つのオブジェクトへのポインターを減算する動作はundefinedです。標準は、何をすべきかについて文字通り何も述べていません。
実際には、コンパイラーはおそらくポインター減算のための最も単純なコードを生成し、その単純なコードはおそらく無関係のポインターを比較可能であるかのように扱います。
プログラムの出力を考えると、b
とd
がたまたま隣り合って割り当てられる可能性があります。宣言された変数を宣言した順序で割り当てる必要があるということは何もありません。オブジェクトを定義された順序でメモリに割り当てたい場合は、オブジェクトを に入れるstruct
か、配列の要素にします。
また、同じプログラムを別のシステムで実行した場合、同じシステムで別のコンパイラを使用した場合、または同じシステムで同じコンパイラを別のコンパイラ オプションを使用して実行した場合、同じプログラムでも異なる結果が得られる可能性があります。原則として、すべてが同じでも、月の満ち欠けが異なると、異なる動作をする可能性さえあります。
また、コンパイラは、コードの動作が適切に定義されていると仮定し、その仮定が与えられた場合にのみ有効な変換を実行することが許可されています。実際には、関連のない 2 つのポインターを減算することにより、コンパイラーに対して、それらが両方とも同じ配列オブジェクトの要素を指すか、その末尾を少し過ぎたところ (単一のオブジェクトが 1 要素の配列として扱われる場合) を指すことを約束したことになります (または、その両方を指すことになります)。は null ポインターです (これが C と C++ の違いの 1 つです)。あなたはコンパイラに嘘をつきました。つまり、それ以上の義務はありません。
そうしないでください。