構造体のパックの仕様の違いについて

このQ&Aのポイント
  • 構造体のパックの仕様の違いにより通信プログラムが正常に動作しない問題が発生しています。
  • linuxとWindowsで構造体のパックの方法が異なり、データの受け渡しに問題が生じる可能性があります。
  • どちらかのパックの仕方を他方に合わせることで問題を解決することができます。
回答を見る
  • ベストアンサー

構造体のパックの仕様の違いについて

仕事でlinuxで動いているサーバーとwindowsで動いているサーバーとで通信するプログラムを開発しています。通信するデータは構造体のデータをそのままやりとししています。 ところがlinuxとVisual Studioで構造体のパックのしかたが違うためにうまくいかないケースがあって困っています。 struct aaa { long long a; int b; }; この構造体についてsizeof(struct aaa) が linux(CentOS 5.3 i386) のgccだと12バイト、Visual Studio 2008(32ビット) だと16バイトになってしまいます。このためにサーバークライアントのデータの受け渡しがうまくいきません。 解決するにはどうすればよろしいでしょうか? 何らかのスイッチを指定することによりどちらかのパックの仕方をもう一方に合わせる事ができればよいのですが。

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

  • ベストアンサー
  • goosyu
  • ベストアンサー率58% (36/62)
回答No.6

VisualStudioからなら・・プラグマ使ってコード上に記述追加,またはコンパイラオプションで対応できます。 #pragma pack (4) /Zp4 サイズは12バイトになりますが実際にどうならぶかは検証が必要です。

moritan2
質問者

お礼

ありがとうございました。 おかげさまで解決しました。

その他の回答 (5)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.5

一番簡単なのは、構造体の各メンバを文字列に変換して扱う方法です。 そうでないなら、データ長と内部表現(負値の扱いやバイトオーダーなど)を厳密に規定する必要があります。 現物合わせでたまたまうまくいったとしても、(64ビット対応など)将来のOSやコンパイラのバージョンや、別のプラットフォームが増えた場合のことを考えると、不安はつきないはずです。

回答No.4

>解決するにはどうすればよろしいでしょうか? パッキング(アライメント)を変更するオプションはありますが、 同じソースを別環境で使用する際には開発環境に依存するような作り方はよくありません。 特に、int型はシステム依存型です。単純なアライメントの変更だけでは解決できません。 Byte型の配列に対して、それぞれのメンバ変数の必要な部分を入れる等のような方法をとるべきです。

moritan2
質問者

お礼

ご回答ありがとうございます。 > パッキング(アライメント)を変更するオプションはありますが、 > 同じソースを別環境で使用する際には開発環境に依存するような作り方はよくありません。 アラインメントを変更する方法が分かれば問題は解決します。そもそも、linux で動いているサーバとwindows出動いているクライアントなのでソースは全く別物です。

  • midly
  • ベストアンサー率40% (24/59)
回答No.3

適当にやるのなら、ダミーをかませて巧くいく方法をカットアンドトライで試すのもいいと思いますが、 違う処理系との通信を厳密に行うのなら、長さや符号やエンディアンの情報を決めてやり取りした方がよいかと思います。 パックの仕方もそうですが、型のビット数やsigned/unsignedを省略したときのデフォルト設定やエンディアンなど 処理系によって仕様が異なり、更にその仕様内容が保証されていないようなものであれば、その仕様には頼らないほうが無難かと思います。 例えば、全メンバが64ビットに収まるのであれば、送信元が構造体の全メンバを一旦64ビット無符号リトルエンディアンに変換し、 通信自体は単なるデータ列として送信し、それを受信側で構造体に再変換するとか。

moritan2
質問者

お礼

ご回答ありがとうございます。 ただ、4バイトのダミーを入れるのは、この問題が発生した時からやっております。構造体のメンバーが変わるたびに、コメントにしたり、しなかったりするのが面倒なのでこの質問をしています。 エンディアンは両方インテル系なので問題ありません。signed、unsigned が問題になるような書き方はしておりません。

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

もっとまっとうな方法は #pragma を使うことかもしれません。 両方の OS で使えればよいのですが…。

moritan2
質問者

お礼

ご回答ありがとうございます。 #pragma を両方で使える必要はなく、 たとえばgccの方を#oragma またはコマンドラインスイッチで8バイトアラインメントにできればよいのですが。あるいはVsual Studioの方を#pragma またはスイッチで4バイトアラインメントにする方法が分かれば解決するのですが。

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

a と b の間に 4 バイトのダミー・メンバーを入れると、 もしかしたら両 OS での構造体サイズが同じになるかもしれません。 とりあえず動けばよいのであればこの方法が使えるかもしれませんし、 本格的に対処するなら識者のかたがたから届くであろう別の方法をお使いになるのがよいかもしれません。

moritan2
質問者

お礼

ご回答ありがとうございます。 ただ、4バイトのダミーを入れるのは、この問題が発生した時からやっております。構造体のメンバーが変わるたびに、コメントにしたり、しなかったりするのが面倒なのでこの質問をしています。

関連するQ&A

  • C#で構造体の配列を持った構造体を使いたいのですが

    C#で構造体の配列を持った構造体を使いたいのですが Cならば struct xyz { struct abc _abc[32]; int index; }; struct abc { int a; int b; int c; }; struct xyz _xyz[8]; xyz[0]._abc[3].b = 1; のような使い方で という感じで やっていた事を C#で 同じような事をやろうとしても うまくいきません うまくやる方法をどなたかご存知ないでしょうか Visual Studio 2005行った場合 コンパイルで 構文エラーです。不適切な配列の宣言子です。マネージ配列を宣言するには、次元指定子を変数の識別子の前に指定します。固定サイズ バッファ フィールドを宣言するには、フィールド型の前に fixed キーワードを使用します となり fixed をつけると 固定サイズ バッファの型は次のうちの 1 つでなければなりません: bool、byte、short、int、long、char、sbyte、ushort、uint、ulong、float または double となってしまいます

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

    構造体の初期化の時にポインタを入れるにはどうしたらいいですか? 例えば、このような構造体で↓ 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" }; というようにできるのですが・・・

  • 構造体を型の異なる構造体に代入

    C言語初心者です。 今回の質問は入力された構造体のメンバのデータを型の異なる構造体に代入したいのですが、毎回コンパイラにおこられてしまいます(汗)具体的には typedef struct MSG{ longint type; int flg; int Dt[64]; }t_msg; このDt[64]を以下の構造体に代入します。 typedef struct SC_MSG{ char a; char b; short c; char d; char e; short f; }t_sc_msg; その際、異なる関数で処理するため、 main(){ foo(&t_msg); }; void foo(t_msg *pt_msgdt){ t_sc_msg = (*pt_msgdt+8); ココがエラーになってしまいます。 何か、根本的な間違いをおかしている気がします。 ご指導の方、宜しくお願いします。 ちなみにOSはLinuxでコンパイラーはgccです。

  • 構造体について

    linuxのソースコードを呼んでいる者ですが、構造体について、実際に使う方法が分かりません。 ソースコードを少し書き換えて改良したいのですが、構造体が定義されているので、それをそのまま引用しないといけないので分からなくなってしまいました。 例えば、それぞれの関数のなかで最初の変数宣言の部分にstructが付いているものもあれば、付いていないものもあります。 この差はなんなのでしょうか?

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

    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つよろしくお願いします。

  • データ数の多い構造体配列について

    visual c++で配列をメンバーに持つ構造体配列を定義したいと思っています。 しかし、以下のように定義してもプログラムが実行されません。 配列の容量が大きいのかもしれませんが、 大量のデータを扱いたいので容量を小さくはしたくありません。 大量のデータを扱うのに何かいい方法はないでしょうか。 struct X { double A[1000]; }; : : : struct X B[10000];

  • 構造体の静的な初期化

    構造体の静的な初期化で、初期化が書かれていないメンバーは、 どうなるのでしょうか。。? たとえば・・・ // 構造体の宣言 strcut MY_STRUCT {    int data1 ;    int data2 ;    int data3 ;    int data4 ; } ; // 変数宣言&初期化 static strcut MY_STRUCT st = {    .data1 = 100,    .data3 = 300 } ; ネットで調べると、 初期化で指示されていないメンバーは0に初期化される、 という記述も一つだけ見つけたのですが・・・これはC言語(C99)の仕様でしょうか? それともコンパイラ依存の仕様でしょうか?

  • 構造体から他の構造体への代入

    現在C言語で簡単なプログラミングを書いているのですが、 構造体(1)(下記参照)から、構造体(2)(下記参照)への代入の方法がわからず悩んでいます。もしよければ手を貸してください!! 標準関数などがないということはわかったので、 地道に代入を行いたいです。 イメージ・・・(data[n].b = moji[n].d;) (1)struct list_kouzou{ int a; char b[30]; char c[8]; }data[100]; (2)struct list_tai{ char d[30]; }moji[15];

  • OVERLAPPED構造体が分かりません・・。

    シリアルポートで非同期データ通信するプログラム作成初歩段階です。 ReadFileの第5引数にはOVERLAPPED構造体へのポインタを指定することは分かったのですが。この構造体の各メンバにどんな値を入れたらいいのか分りません・・・。 よろしくお願いします。 typedef struct _OVERLAPPED { ULONG_PTR Internal; ULONG_PTR InternalHigh; DWORD Offset; DWORD OffsetHigh; HANDLE hEvent; } OVERLAPPED;

  • JavaからC構造体にパケット通信する方法

    ネットワークプログラミングの初心者です。 現行のシステムがC言語で実装されているUDP送受信アプリに対して、 この度、Javaクライアントでも連携をおこなうことになりました。 しかし、現行のシステムはクライアントとサーバ間でC構造体をUDPにて送受信しています。 JavaでC構造体と同様のデータを作成しUDP送信、またサーバからUDP受信したデータをJavaで使用できる型変換する方法はありますでしょうか。 JNIやJNAを使用しない方法で、ご教授いただけますでしょうか。 以下にC構造体の例を記載いたします。 typedef struct udp_data { long b_type; long a_type; char userid[128]; char passward[128]; } UDP_DATA;

    • ベストアンサー
    • Java

専門家に質問してみよう