• ベストアンサー

アドレスの計算が合わない

C++でポインタの勉強をしています。 その中でアドレスについての以下のような記述がありました。 <例1> struct { int a; int b; int c; } oshiete; cout << &oshiete.a << endl; cout << &oshiete.b << endl; cout << &oshiete.c << endl; このように、構造体の中で宣言された変数の領域は連続した場所を確保するというものでした。これの実行結果は以下の様になりました。 0013FF5C 0013FF60 0013FF64 int型のバイト数は4でしたので、それぞれの変数の先頭アドレスは4つ間隔になっています。しかし、これの2つ目の変数bをshort型に変えても同じ結果が返ってくるのです。short型のバイト数は2です。 <例2> struct { int a; short b; int c; } oshiete; cout << &oshiete.a << endl; cout << &oshiete.b << endl; cout << &oshiete.c << endl; 結果: 0013FF5C 0013FF60 0013FF64 そして変数aもshort型にすると、やっと納得のいく結果になりました。 <例3> struct { short a; short b; int c; } oshiete; cout << &oshiete.a << endl; cout << &oshiete.b << endl; cout << &oshiete.c << endl; 結果: 0013FF60 0013FF62 0013FF64 なぜ<例2>ではint, short, intの順で宣言したのにアドレスが全て4つ間隔なのでしょうか?例えば先頭アドレスが0013FF5Cであるなら、 0013FF5C 0013FF60 0013FF62 のように1つ目と2つ目のアドレス差は4、2つ目と3つ目のアドレス差は2になるはずだと思うのですが。

質問者が選んだベストアンサー

  • ベストアンサー
  • noocyte
  • ベストアンサー率58% (171/291)
回答No.4

↓詳しい説明 データ型のアラインメントとは何か,なぜ必要なのか? http://www5d.biglobe.ne.jp/~noocyte/Programming/Alignment.html

その他の回答 (4)

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.5

>なぜ<例2>ではint, short, intの順で宣言したのに >アドレスが全て4つ間隔なのでしょうか? なぜ、こうなるかは他の方もおっしゃっていますが、 コンパイラによるアライメントの問題です。 勝手にこうされると困ることもあるので、 明示的にアライメントを1バイト単位にする事で、 この様なことを防ぐことが出来ます。 以下に紹介する例はVC6で確認しています。 #include <iostream.h> struct {  int a;  int b;  int c; } oshiete1; struct {  int a;  short b;  int c; } oshiete2; #pragma pack(push,1) struct {  int a;  short b;  int c; } oshiete3; #pragma pack(pop) int main( void ) {  cout << "oshiete1(b is int)" << endl;  cout << &oshiete1.a << endl;  cout << &oshiete1.b << endl;  cout << &oshiete1.c << endl;  cout << "oshiete2(b is short and non pack)" << endl;  cout << &oshiete2.a << endl;  cout << &oshiete2.b << endl;  cout << &oshiete2.c << endl;  cout << "oshiete3(b is short and pack 1)" << endl;  cout << &oshiete3.a << endl;  cout << &oshiete3.b << endl;  cout << &oshiete3.c << endl;  return 0; } ただし、pragmaの動作は環境に依存するので、 お使いのコンパイラにはこの機能が無いものも 存在します。

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.3

> 構造体の中で宣言された変数の領域は連続した場所を確保する 必ずしも、そうなりません。 今回経験なさったように、構造体のメンバーどうしの間に すきま(パディングといいます)が入ることは、 ごく普通にあります。

noname#96023
noname#96023
回答No.2

昔勉強した知識程度ですが OSがメモリにアクセスする時はワード単位でアクセスします。 32bitOSなら一般に4バイトで1ワードです で、変数bをshort型にしてメモリアドレスを詰めると、必然的に変数cはワードをまたぐことになります。 その結果、変数cにアクセスするには2ワード読み出す必要が出てしまいます。 コンパイラの最適化オプションを外せばアドレスが詰まって確保される気もしますがね。。。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

アライメントの指定をしていないからですよ C++のマニュアルで アライメントとか #pragma packなどについて調べてみましょう 80386以降のx86CPUの場合4の倍数になっていないアドレスの参照は効率が低下します VC++の場合 構造体はいずれかのメンバーの最大のアライメントにそろえることになっていますのでWin32の場合 int short intなら 4バイト境界にそろえられることになります

関連するQ&A

  • char型変数のアドレスを coutで表示するには

    #include <iostream> using namespace std; int main() { bool b; int i; short s; long l; float f; double d; char c; //上で宣言した変数のアドレスを表示 cout << "bool &b " << &b << endl; cout << "int &i " << &i << endl; cout << "short &s " << &s << endl; cout << "long &l " << &l << endl; cout << "float &f " << &f << endl; cout << "double &d " << &d << endl; cout << "char &c " << &c << endl; //「char &c 」とのみ表示される cout << '\n'; //char型のみ printf で再表示 printf("char &c %p\n", &c); //「char &c ********」と表示される return 0; } 上のプログラムを実行すると cout << "char &c " << &c << endl; のところだけ、アドレスが表示されません。 printfを使えば、char型の変数のアドレスも表示されるのですが…。 coutを使ってchar型のアドレスを表示させるにはどうすればいいのでしょうか。 よろしくお願いします。

  • 構造体のサイズが意味不明の数になります・・・

    構造体のサイズのことですが、ご存知の方がいたら教えてください。 まず、↓のプログラムを実行させたのですが、 #include<iostream> using namespace std; struct test{ short a; int b; short c; }; int main(){ cout<<sizeof(test); return 0; } 結果として8が出力されることを予想していましたが、なぜか12が出力されました。 shortは4バイトだったのかな、と思ったのですが cout<<sizeof(short); でやってみたところ結果はやはり2でした。 もちろん cout<<sizeof(int); の結果は4です。 さらに分からない所は struct test{ int b; short a; short c; }; int main(){ cout<<sizeof(test); return 0; } このように構造体の中身を入れ替えたところ正しく8が出力されました。 visual c++ 2008 express editionを使っています。 OSはvistaです。

  • VC++でプログラムの勉強をしています。

    プログラムは最近はじめたばかりです。While文とif文を使ってクイズを作ってみたところ、一個目のsinで入力を求めているところから無限ループになってしまいました。色々調べてcin.cler()とsin.ignore()を入れたりもしてみましたが上手くいきませんでした。どこを間違えているのでしょうか? //クイズ #include <iostream> using namespace std; int main()//cin.clear();cin.ignore();???? { int a; int b; while(1) { cout<<"ネコ型のロボットが出てくるアニメといえば?"<<endl; cout<<"A)ドラえもん B)ドラエもん C)ほりえもん D)サザエさん"<<endl; cin>>a; if(a=='A') { cout<<"ファイナルアンサー?"<<endl; cout<<"Y)Yes N)NO"<<endl; cin>>b; if(b=='Y'){break;} if(b=='N'){cout<<"ゆっくり考えてね!!"<<endl;} if(b!='Y'||'N'){cout<<"正しく入力してね!"<<endl;} } if(a=='B'||'C'||'D') { cout<<"ファイナルアンサー?"<<endl; cout<<"Y)Yes N)NO"<<endl; cin>>b; if(b=='Y'){cout<<"残念!!"<<endl;} if(b=='N'){cout<<"ゆっくり考えてね!!"<<endl;} } if(a!='A'||'B'||'C'||'D'){cout<<"正しく入力してね!"<<endl;} } cout<<"正解!!"<<endl; }

  • c++11での文字列リテラルの特殊化について

    c++11言語でのテンプレート部分特殊化についての質問です。 コメントアウト部分は出力結果です template<class T> struct VT { static const int type = 1;}; template<class T,int N> struct VT< T[N] > { static const int type = 2;}; template<class T,int N> struct VT< const T[N] > { static const int type = 3;}; template<class T> struct VT< T* > { static const int type = 4;}; template<class T> struct VT< const T*const > { static const int type = 5;}; #include<iostream> #include<typeinfo> int main(){ std::cout<<"A:"<< VT< char >::type << std::endl; // A:1 std::cout<<"B:"<< VT< char[10] >::type << std::endl; // B:2 std::cout<<"C:"<< VT< char* >::type << std::endl; // C:4 std::cout<<"D:"<< VT< char const [1] >::type << std::endl; // D:3 std::cout<<"E:"<< VT< decltype("") >::type << std::endl; // E:1 std::cout<<"G:"<< typeid( char const [1] ).name() << std::endl;// G:char const [1] std::cout<<"H:"<< typeid( "" ).name() << std::endl;// H:char const [1] } 型名を直接記述したD,G、文字列リテラルを記述したE,H。 コンパイラ毎の差はあれど、GとHの型名は同じものが表示されます。 ですが、[D:3] [E:1]と値は違い、別の特殊化テンプレートが使われています。 この部分が分かりません。 また、配列リテラル、文字列リテラルに対し部分特殊化テンプレートを宣言する方法などありましたら、ご教示お願いします。

  • スコープ外でのアドレスの参照についての疑問

    C++を勉強していて解らないことがあったので質問させていただいたのですが、 とあるスコープで生成したインスタンスを、 スコープ外で参照しても問題なく値が取り出せるのですけども、 これは処理的には問題ないのでしょうか? 例のソースを以下に示します。 struct Hoge {  int a, b; }; void testA(){  Hoge *hoge;  if( true ){   Hoge tmp;   tmp.a = 1;   tmp.b = 2;   hoge = &tmp;  }  std::cout << hoge->a << "," << hoge->b << std::endl; } void testB(){  Hoge *pHoge;  if( true ){   Hoge *pTmp = new Hoge();   pTmp->a = 1;   pTmp->b = 2;   pHoge = pTmp;  }  std::cout << pHoge->a << "," << pHoge->b << std::endl;  delete pHoge;  pHoge = NULL; } 上記の場合、どちらも画面に 1,2 と出力されますが、 アドレスが上書きされていないだけで今の時点では偶然エラーが出ないけども潜在的なバグがあったり、 処理的にいつ落ちるかわからないなどの問題はあったりしますか? ご存知の方がいらっしゃいましたらアドバイスをお願いします

  • static変数のループ内での処理

    以下のc++ソース内で、static int b = 100;という式ですが、 1回目に、ここの処理を通ったときに静的変数が作成されると思います。 2回目のループのときに、ここでまたb=100と初期化されています。 ですが、ループを重ねるごとに、カウントが1増えていきます。 staticなので、これは期待通りの動作だとは思うのですが、なぜそうなるのかがわかりません。 コンパイラなどが、staticが頭に付いたものは、2度目のループ以降はこの行を無視するように しているのでしょうか? もしそうなら、他に暗黙のルール?のようなことが他にもあるのでしょうか? 考えるとさらにc++がわからなくなってきました。 #include <windows.h> #include <iostream> using namespace std; void test(){ int a = 100; cout << a << " " << &a << endl; static int b = 100; cout << b << " " << &b << endl; b++; int * abc = new int [10]; abc[0] = 9999; cout << abc <<" "<< &abc << " " << abc[0] << endl; delete [] abc; } int main(){ while (1){ Sleep(2000); test(); } } 教えてください。 よろしくお願いいたします。

  • 今,C++のコンストラクタを勉強しているのですが,これの働きと役割がい

    今,C++のコンストラクタを勉強しているのですが,これの働きと役割がいまいちわかりません class const{ public: int a; const(); } const::const() { a = 100; } int main() { const c; cout << " c.a = " << c.a << endl; return 0; } この様な例がのっていたのですが、[const c;]は何を定義しているのでしょうか, [c.a]はどの変数のことをさしているのでしょうか?教えてください。

  • ''C++の条件分岐分からないんですが

    #include<iostream> using namespace std; int main(){ int a; cout << "数値を入力してください\n"; cin >> a; if( a > 30) cout <<"31以上ですね\n"; } else if(a<10){ cout <<"10未満ですね\n"; } else { cout <<"30以下で10以上ですね\n"; } return 0; } これが例文なんですが、 変数aの値がbより小さい場合には、『aはbより小さいです』と表示させ、大きい場合には"a=a+b"を計算させる 文字変数mの中身が'a'ならば、『aが格納されています』と表示させて、'a'でないならば『'a'でない文字が格納されています』と表示させたあと、変数bとcを使った『b=b+c』を計算する。 変数aが、変数bより小さい場合には、『aはbより小さいです』と表示し、変数bより大きい場合には、『aはbより大きいです』と表示し、変数bと等しい場合には、『aとbは等しいです』と表示する #include<iostream> using namespace std; int main(){ int a; if(a < b) { __cout("aはbより小さいです\n"); } else { __c = a + b; }return 0; } #include<iostream> using namespace std; int main(){ int a; if(m == 'a') __cout("aが格納されています\n"); } else { __cout("\'a\'でない文字が格納されています\n"); } return 0; } #include<iostream> using namespace std; int main(){ int a; if(a < b) { __cout("aはbより小さいです\n"); } else if(a == b) { __cout("aとbは等しいです\n"); } else { __cout("aはbより大きいです\n"); } return 0; } これ合ってますか?あとプログラミング環境すらないので実行結果教えてもらっていいですか?

  • 条件の配列

    表題の件に付いて質問させていただきます。 複数の条件分岐を簡便に記述する方法を探しております。 簡単な例でいいますと、 int main(){  int value=3;  if(value==0)std::cout <<"value="<<0 <<std::endl;  if(value==1)std::cout <<"value="<<1 <<std::endl;  if(value==2)std::cout <<"value="<<2 <<std::endl;  if(value==3)std::cout <<"value="<<3 <<std::endl; } 上記プログラムの複数の条件分岐をfor文をもちいてかきかえる場合、conditionクラスを作成して class condtion{ private:  int *a;  int b; public  void SetPointer(int* value){a=value}  void SetVal(int val){b=val}  bool isTrue(){   if(*a==b){return true;}   else{ return faulse;}  } } int main(){  int value=3;  condition c[4]; //クラス  for(int i=0;i<4;i++){   c[i]->SetPointer(&value);   c[i]->SetVal(i);  }  for(int i=0; i<4; i++){   if(c[i].isTrue())std::cout<<"i="<<i<<std::endl;  } } と実装できそうな気がするのですが、(上記プログラムは動作確認しておりません。) 変数が増えたり、条件が複雑になると少々繁雑になってしまいそうな気がしております。 もっと簡便に条件分岐を配列として処理する方法は存在しますか? 関数ポインタなどがつかえるのでしょうか? アドバイスよろしくお願いいたします。

  • mainの外に変数 vs ポインタ渡し

    C++についての質問です。プログラミング初心者ですが、よろしくお願いします。 最近、関数の外側でも変数を宣言できることを知りました。関数の外側で変数を宣言すると、全ての関数でその変数にアクセスすることができ大変便利なように思います。 「わざわざポインタ渡しなどする必要はないのでは?」と思ってしまいました。 これは何か問題があるのでしょうか? 初心者の言葉で説明しても理解しにくいかと思いますので、例として「足し算するプログラム」を以下に記載します。 ポインタ渡しで書くと、以下のような感じになるかと思います。 //●ポインタ渡し #include "stdafx.h" #include <iostream> void func(int x,int y,int *pans){ *pans = x+y; } void main(){ int a=10, b=20, ans; func(a,b,&ans); std::cout << ans << std::endl; } しかし、mainの外に変数を宣言すれば //●mainの外に変数 #include "stdafx.h" #include <iostream> int a,b,ans; void func(int x,int y){ ans = x+y; } void main(){ a=10; b=20; func(a,b); std::cout << ans << std::endl; } ansをポインタ渡しする必要なく、funcの計算結果をansに代入できました。 「●mainの外に変数」のプログラムはどのような問題や危険性を孕んでいるのでしょうか? 以上になります。長文お読みいただきありがとうございました。 よろしくお願いいたします。

専門家に質問してみよう