• ベストアンサー

構造体のメモリの確保のされかた

2つ質問があります。 1. #include <iostream> using namespace std; union Data { unsigned long val1_val2; struct { unsigned short val1; unsigned short val2; } value; }; int main(void) { Data data; data.val1_val2 = (40 /* val1 */ << (sizeof(data.value.val1) * 8)) + 10 /* val2 */; cout << "val1 = " << data.value.val1 << endl; cout << "val2 = " << data.value.val2 << endl; return 0; } 上記ソースコードを実行すると、「val1 = 10 val2 = 40」という結果がでます。val1は上位2バイトを指しているはずだと考えて書いたのですが、何が間違っているのでしょうか? 構造体は上に書いたメンバーを下位に割り当てていくのでしょうか? 2. 32ビットコンピューターでは構造体のサイズは4の倍数バイトになると聞いたのですが、VC++で struct s1{ char c; }; のサイズをsizeof演算子で見てみると、1バイトで struct s2{ unsigned bit: 1; }; のサイズは4バイトでした。 前者は本当に1バイトで扱われているのでしょうか? 以上2つよろしくお願いします。

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

  • ベストアンサー
  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.4

>ところで、intとcharを含む6バイトの構造体はパディングがされて8バイトになるのに、char6つの構造体はどうして6バイトになるんでしょうか? コンパイラの設定でパディングを詰める設定にすれば struct A{ char a; int c; }; も5バイトになります。 ただパディングを詰めると一般的に処理速度が落ちます。 long(int)は4の倍数のアドレス、shortは2の倍数に置くと処理が速いのです。 また一般的に32bitCPU(Pentium4等)ではcharよりintの計算の方が速いです。 メモリー alignment(アライメント)で調べてみてください。

minimax2005
質問者

お礼

回答ありがとうございます。 charよりintのほうが速いというのは知りませんでした。 基本データ型なのにって気もちょっとしますね。

その他の回答 (3)

回答No.3

> intとcharを含む6バイトの構造体はパディングがされて8バイトになるのに、 > char6つの構造体はどうして6バイトになるんでしょうか?  環境によって異なりますが、CPUは変数のサイズによってアクセスできる、或いはしやすいアライメントというものが存在します。  そのアライメントを整えるためにパディングを行うわけですが、考え方としてその構造体を配列としてもアライメントが保てるようにパディングされます。

参考URL:
http://plaza.harmonix.ne.jp/~fakira/cppdoc/alig.htm
minimax2005
質問者

お礼

回答ありがとうございます。 リンク先のページは参考になりました。

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.2

>1に関しては#1さんの言われるとおり。 「リトルエンディアン: little endian」と 「ビックエンディアン: big endian」 で調べてください。 http://e-words.jp/w/E383AAE38388E383ABE382A8E383B3E38387E382A3E382A2E383B3.html http://e-words.jp/w/E38393E38383E382B0E382A8E383B3E38387E382A3E382A2E383B3.html 人間の感覚的にはビックエンディアンが扱いやすいように思えるかもしれませんが アセンブラをやってる人にはリトルエンディアンの方が扱いやすいと思います。 多倍長の足し算とか書けばわかりますが 下桁から足していかないと繰り上がるかどうかが わからないためビックエンディアンだと 先頭ではなく後ろのバイト から見ていく必要があるのです。 >2.32ビットコンピューターでは構造体のサイズは4の倍数バイトになると聞いたのですが パディングと勘違いしていませんか? #include <stdio.h> struct A{ char a; int c; }; int main(){ printf("%d\n",sizeof(A)); return 0; } 上記コード VCやBCC,gccのデフォルトでは普通8になりますが パディングを詰める設定にすれば5になります。

minimax2005
質問者

お礼

回答ありがとうございます。 リトルエンディアン、ビックエンディアンという用語ははじめて知りました。 計算のしやすさに違いがあるんですね。 >パディングと勘違いしていませんか? どうやら勘違いしていたようです。 ところで、intとcharを含む6バイトの構造体はパディングがされて8バイトになるのに、char6つの構造体はどうして6バイトになるんでしょうか? char型の場合はそのままのほうが扱いやすいのでしょうか?

  • don_go
  • ベストアンサー率31% (336/1059)
回答No.1

1) val1_val2 の値が16進数で、0x0028000Aになるはずだから val1 に0x0028(40)、val2 に0x000A(10)が入るはずだと 言うのでしょうが、Intel86系のCPUでは、0A 00 28 00 の 順序でLongの値がメモリに格納されます。 0x0028 0x000A は、それぞれ 28 00 と 0A 00 の順序で shortの値が格納されます。 (上位バイトと下位バイトが逆に並ぶ) 2) 32ビットコンピューターでは構造体のサイズは4の倍数バイトになると聞いたのですが どこで、そんな話を聞きました??

minimax2005
質問者

お礼

回答ありがとうございます。 逆順にデータが格納されるのは知りませんでした。 よく構造体のデータ配置の図では先頭からデータを配置しているかのように図が書いてあるので、間違って覚えてました。 >どこで、そんな話を聞きました?? たとえばhttp://www.ncad.co.jp/~komata/c-kouza7.htmとかに。 コンピュータが計算しやすいように詰め物をしてバイト数をあわせるらしいのです。

関連するQ&A

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

    構造体のサイズのことですが、ご存知の方がいたら教えてください。 まず、↓のプログラムを実行させたのですが、 #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です。

  • C++/CLIの構造体のコンストラクタについて

    C++/CLIの構造体のコンストラクタについて C++/CLIで、固定サイズの配列を持つ構造体を、次のようにコーディングして使っています。 value struct AAA { public:   array<unsigned short>^ m1;   AAA(unsigned short dummy)   {     m1 = gcnew array<unsigned short>(4);   } }; AAA ^struct0 = gcnew AAA(0); この方法で正常に動作するのですが、2点ほど気になる点があります。 (1) コンストラクタAAA(unsigned short dummy)を実装しなくても済む方法がないか? (2) この方法では、struct0を、ネイティブヒープ領域に割り当てられない (AAA *struct0 = new AAA(0))でコンパイルエラー) (1)と(2)は関連する気もするのですが、これらを解決する方法はあるのでしょうか?

  • C言語の構造体のサイズについて

    いつもお世話になっていります。 早速ですが、C言語の構造体のサイズについて教えてください。 typedef struct B { short code; char name; float price; } B; typedef struct A { B bbb[10]; double sougaku; } A; A aaa; といった構造体があった場合に、 sizeof(aaa.bbb.code) + sizeof(aaa.bbb.name) + … + sizeof(aaa.sougaku) という風に一つ一つサイズを取得し、合計して構造体のサイズを取得した場合と sizeof(aaa) という風に構造体のサイズを取得した場合のサイズの値が異なるといった現象が起きます。 その原因が分からなくて困っております。 そこで考えられる要因をお教えください。 因みに実際の構造体はサイズで言えば2500バイトくらいあります。 froat/char/double/short 型を使用しております。 よろしくお願いします。

  • 構造体の中でユーザー定義型の型を使いたい TurboC → VC++2005

    昔、TurboCで作ったソースをVC++2005に置き換えようと難儀しています。 以下、構造体の中でユーザー定義型の型を使いたいのですが、 方法がわからず困っています。 ソースは途中で、コンパイルエラーになりませんが、肝心な所は コメントになっています。 詳しい方、教えていただけますか? /* 昔の古い構造体を VC++2005で使いたいです。 typedef struct _Test1{ char key[128]; char val[10]; } Test1; typedef struct _Test2{ char key[128]; Test1 val[10]; } Test2; */ #include <memory.h> using namespace System; using namespace System::Runtime::InteropServices; // テンプレート?でcharやshort型の配列はできるみたいです。 template<typename TYPE, size_t size> [StructLayout(LayoutKind::Sequential, Size=sizeof(TYPE) * size)] public value struct native_array{ TYPE elem; property TYPE default[int] { TYPE get(int index) { pin_ptr<TYPE> p = &this->elem; return p[index]; } void set(int index, TYPE value) { pin_ptr<TYPE> p = &this->elem; p[index] = value; } } }; public ref struct Test1{ String^ key; native_array<char, 10> val; Test1(){ key = "test1だよ"; pin_ptr<char> p = &this->val.elem; array<char>^ data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; pin_ptr<char> dat = &data[0]; memcpy(p, dat, sizeof(this->val)); } }; public ref struct Test2{ String^ key; // charやshortなどでなく、ユーザー定義型のTest1の型を // 配列として10個確保したい // 記述方法がわかりません。 Test2(){ key = "test2だけど、test1の型を使いたいです。"; // 記述方法がわかりません。 } }; int main(array<String^>^ args){ Test1 test1; Test2 test2; // Test1 Console::WriteLine(test1.key); for (unsigned i = 0; i < sizeof(test1.val) / sizeof(test1.val[ 0 ]); ++i) { Console::WriteLine(test1.val[ i ].ToString()); } // Test2 Console::WriteLine(test2.key); // 記述方法がわかりません。 return 0; }

  • 複数のライブラリをリンクするときに構造体が衝突する

    C++,開発環境はVisual Studio Professional 2013です, ライブラリ1にxy座標の構造体 struct point { int x; int y; }; を定義しています. ライブラリ2にも全く同じ構造体を定義しています. ここで,あるプロジェクトからこれら2つのライブラリをリンクしようとしたら, error C2011: 'point' : 'struct' 型の再定義 というコンパイルエラーが出ます. ライブラリ1とライブラリ2にpoint構造体が記述された共通用のヘッダを参照させるという方法をとれば解決できるのでしょうが,この方法以外でこのエラーをなんとか回避する方法はないでしょうか. 構造体宣言は只の宣言であって実体をもたないため,中身が同じであればいくら記述が重複しても問題はないと聞いたことがあったので大丈夫だと思っていました. また,ライブラリ1とライブラリ2のpoint構造体の名前それぞれpoint1,point2にするなど違うものにするという方法でも回避できるのでしょうが,下記のメインコード内でコメントアウトされている部分のように,構造体の中身が全く同じなので互換性を持たせられるようにしたいのです. ちなみに,ライブラリ1,2はコンソールアプリケーション・空のプロジェクトで作成したあと,ソリューションのプロパティで「構成の種類」を「スタティックライブラリ(.lib)」にするという手順で作成しています. 以下,簡略コード ====ライブラリ1==== ----lib1.h---- #ifndef _H1_ #define _H1_ struct point { int x; int y; }; void print_lib1(struct point p); #endif ----lib1.cpp---- #include "lib1.h" #include <iostream> void print_lib1(struct point p) { std::cout << "lib1 : " << p.x << ", " << p.y << std::endl; } =====ライブラリ2====== ----lib2.h---- #ifndef _H2_ #define _H2_ struct point { int x; int y; }; void print_lib2(struct point p); #endif ----lib2.cpp---- #include "lib2.h" #include <iostream> void print_lib2(struct point p) { std::cout << "lib2 : " << p.x << ", " << p.y << std::endl; } ===メインコード=== ----main.cpp---- #include "../../lib1/lib1/lib1.h" #include "../../lib2/lib2/lib2.h" int main(void) { struct point val; val.x = 2; val.y = 3; print_lib1(val); //print_lib2(val); }

  • 構造体へのポインタについて

    初心者です。 C入門書の著者のサポートページには正誤表とダウンロードしかないためこちらで質問させていただきます。 下記のコードの下から二行目の構造体へのポインタ (Car *) について、中学生に説明するように基本的な考え方、目的、書式、参考URLなどを教えて下さい。 ポインタについては、該当の章を読み直し基本事項については理解しておりますが、突然あるページから(Void *)や(Char *)など括弧で閉じるものが説明なしに出てきてちょっと混乱してます。(汗 どうぞ宜しくお願い致します。 #include<stdio.h> /* 構造体型struct Carの宣言 */ typedef struct Car{ int num; double gas; }Car; int main(void) { printf("int型のサイズは%dバイトです。¥n", sizeof(int)); printf("double型サイズは%dバイトです。¥n", sizeof(double)); printf("構造体structCar型のサイズは%dバイトです。¥n", sizeof(Car)); printf("構造体struct Car型へのポインタのサイズは%dバイトです。¥n", sizeof(Car *)); return 0; }

  • 構造体の初期化の時にポインタを入れるにはどうしたらいいですか?

    構造体の初期化の時にポインタを入れるにはどうしたらいいですか? 例えば、このような構造体で↓ struct PACKET { uint16_t size; // データの長さ uint16_t *data; // データバイト列 }; 初期化の時にsizeとdataを入れるにはどうしたらいいのでしょうか? dataがuint16_t*じゃなくてchar*なら struct PACKET { uint16_t size; // データの長さ char *data; // データバイト列 }; struct PACKET p = { 5, "12345" }; というようにできるのですが・・・

  • 構造体の動的確保について

    ある変数により動的確保を行いたいのですが、構造体中の変数に対して動的確保はできるのでしょうか? struct data{ int i[30]; /*←ここの配列を動的に確保したい*/ double d[40]; /*←ここの配列を動的に確保したい*/ }data1[10]; よろしくお願いします。

  • 動的メモリの確保の仕方を教えて下さい。

    プログラミングの初心者なのですが、現在256x256x100のバイナリファイルを読み込もうとしているのですが、下のように書くとエラーになってしまいます。動的メモリの確保を行えば、上手くいくと思うのですが。。どなたか教えて頂けないでしょうか?どうぞよろしくお願いします。 const short int SIZE=256; const short int SLICE=100; signed short int matrix[SLICE][SIZE][SIZE]; for(int i=0; i<SLICE; i++){ for(int j=0;j <SIZE; j++){ for(int k=0;k<SIZE; k++){ fin.read((char*) &matrix[i][j][k],sizeof(signed short int)); cout<< matrix[i][j][k]<<endl; } } }

  • 構造体のデータを丸ごとコピーしたい

    C言語の構造体の勉強をしています。 構造体のデータを丸ごとコピーしたいのですが、今までは下記プログラムの★1の方法で1つ1つやっていました。 しかし変数が増えてきたのでできれば一度にコピーをしたいのですが、★2の方法では場合によってはゴミが含まれてしまいます。 そこで★3の方法で試すと今のところコピーできたのですが、これは安全なのでしょうか? ご存知の方がおられればお願いします。 また、もっといい方法があればご伝授いただけると助かります。 #include <stdio.h> #include <string.h> struct Sample{  int val1;  int val2; }; void test(Sample *p, int num){  Sample d;  switch(num){  case 1: //★1   d.val1 = p->val1;   d.val2 = p->val2;  break;  case 2: //★2   memcpy(&d, p, sizeof(Sample));   break;  case 3: //★3   d = *p;   break;  }  printf("val1:%d, val2:%d\n", d.val1, d.val2); } int main(){  Sample s;  s.val1 = 1;  s.val2 = 2;  test(&s, 1);  return 0; }

専門家に質問してみよう