0

次のコードが 0 を出力するのはなぜですか? つまり、ポインタ変数がそれらの間で宣言されているにもかかわらず、変数がavariable の直後に配置されるのはなぜですか?dc

#include<iostream>
using namespace std;

int main () {
    unsigned int a = 100;
    unsigned int &b = a;
    unsigned int *c = &b;
    unsigned int d = (unsigned int)(c);
    int e = &d - c;
    int &f = e;
    e ++;
    cout << e << " " << endl;
    return 0;
}
4

3 に答える 3

2

逆方向の作業:

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

結論: のアドレスは のアドレスdsizeof (unsigned int)バイトですa。(ポインター減算は、ポイント先の型のサイズによってスケーリングされます。)

おそらく。

実際、独立して定義された 2 つのオブジェクトへのポインターを減算する動作はundefinedです。標準は、何をすべきかについて文字通り何も述べていません。

実際には、コンパイラーはおそらくポインター減算のための最も単純なコードを生成し、その単純なコードはおそらく無関係のポインターを比較可能であるかのように扱います。

プログラムの出力を考えると、bdがたまたま隣り合って割り当てられる可能性があります。宣言された変数を宣言した順序で割り当てる必要があるということは何もありません。オブジェクトを定義された順序でメモリに割り当てたい場合は、オブジェクトを に入れるstructか、配列の要素にします。

また、同じプログラムを別のシステムで実行した場合、同じシステムで別のコンパイラを使用した場合、または同じシステムで同じコンパイラを別のコンパイラ オプションを使用して実行した場合、同じプログラムでも異なる結果が得られる可能性があります。原則として、すべてが同じでも、月の満ち欠けが異なると、異なる動作をする可能性さえあります。

また、コンパイラは、コードの動作が適切に定義されていると仮定し、その仮定が与えられた場合にのみ有効な変換を実行することが許可されてます。実際には、関連のない 2 つのポインターを減算することにより、コンパイラーに対して、それらが両方とも同じ配列オブジェクトの要素を指すか、その末尾を少し過ぎたところ (単一のオブジェクトが 1 要素の配列として扱われる場合) を指すことを約束したことになります (または、その両方を指すことになります)。は null ポインターです (これが C と C++ の違いの 1 つです)。あなたはコンパイラに嘘をつきました。つまり、それ以上の義務はありません。

そうしないでください。

于 2013-10-15T23:32:53.600 に答える
0

独自のメモリ管理システムを使用してオブジェクトを明示的に配置しない限り、メモリ内でのオブジェクトの相対位置は、コンパイラおよびシステムに依存します。

于 2013-10-15T23:11:14.147 に答える
-1

あなたの行int e = &d - c;は 2 を減算していますunsigned int *

メモリ内で&dは、それから 8 バイト離れcています (システムによって異なりますが、anintは 4 バイトであると想定しています)。事実上、次の方法でスタックを構築します。

unsigned int a = 100;                // &a is 0x0
unsigned int &b = a;                 // &b is 0x0 (it's just an alias)
unsigned int *c = &b;                // &c is 0x4
unsigned int d = (unsigned int)(c);  // &d is 0x8

メモリ内unsigned intで 4 バイトを使用します。したがって、 を実行しているときは、 を&d - c返す必要があります。これは、 (4*2=8);2でポインター演算を使用しているためです。unsigned int*

サイズが 2 (2*4=8)であるため、 int e = (short*)&d - (short*)cresult should で試すことができます。4short

サイズが 1 (1*8=8)であるため、 int e = (char*)&d - (char*)cresult should で試すことができます。8char

理解するために変数とアドレスを出力してみてください:

#include<iostream>
using namespace std;

int main () {
  unsigned int a = 100;
  unsigned int &b = a;
  unsigned int *c = &b;
  unsigned int d = (unsigned int)(c);
  int e = (short*)&d - (short*)c;
  //int &f = e;                                                                                                                                                                  
  //e ++;                                                                                                                                                                        

  cout << "&a: " << (unsigned int)&a << endl;
  cout << "&b: " << (unsigned int)&b << endl;
  cout << "&c: " << (unsigned int)&c << endl;
  cout << "&d: " << (unsigned int)&d << endl;

  cout << endl;

  cout << " a: " << a << endl;
  cout << " b: " << b << endl;
  cout << " c: " << (unsigned int)c << endl;
  cout << " d: " << d << endl;

  cout << endl;

  cout << " e: " << e << endl;
  return 0;
}

ここではint e = (short*)&d - (short*)c;、結果は次のとおりです。

&a: 3220197356
&b: 3220197356
&c: 3220197360
&d: 3220197364

 a: 100
 b: 100
 c: 3220197356
 d: 3220197356

 e: 4
于 2013-10-15T23:52:02.867 に答える