C言語バイトアラインメントの構造体共通体占有バイト数に関する高速計算方法のまとめ


先日、プロジェクトをしていたところ、クライアントとサーバ側が使用している同じ構造体のように見えるソケット通信の問題がありましたが、サーバ側ではクライアントから送信されたデータをすべて印刷できません.長い間エラーを探していたところ、元の両端の構造体は同じように見えたが、両端の構造体が占有するバイト数は異なることが分かった.サーバ側がすべてのコンテンツを正常に表示できないためです.
おそらく、clientエンド定義構造体は次のようになります.
typedef  struct _u64{
    long high;
    long low;

}U64;
struct _data_pack{
    int a;
    int b;
    union snmp_data{
   
       long     name;
       U64  	buf1;
       char 	buf2[100];
   }snmp_data_t;

}data_pack_t;

client
この送信
sizeof(data_pack_t)
の各見出しページがあります.
サービス側の定義は次のとおりです.
typedef unsigned long long U64;
struct _data_pack{
    int a;
    int b;
    union snmp_data{
   
       long 	name;
       U64  	buf1;
       char 	buf2[100];
    }snmp_data_t;

}data_pack_t;

struct data5{

		char c1;
		char c2[2];
};

サービス側もsizeof(data_pack_t)のバイト数をこれだけ受け入れる.
問題が発生し、サービス側では共用体のデータ表示を印刷できないため、原因を調べたところ、元の両側の構造体の大きさが占めるバイト数が異なることが分かった.
クライアント側:sizeof(data_pack_t)=108
サービス側:sizeof(data_pack_t)=112
そのため、本人はネット上で大量のバイトの位置合わせに関する資料を探して、構造体の共用体のバイトの大きさを迅速に計算する方法をまとめて、以下のように説明します:
単純なタイプの変数でも構造タイプの変数でも、コンビネーションタイプの変数では、メモリ内のストレージはバイト整列で格納されます.このようなストレージの主な目的は、cpuがデータに迅速にアクセスできるようにすることです.
バイトの位置合わせといえば、ここではいくつかの重要な概念を深く理解し、記憶する必要があります.
1:バイトの位置合わせとは
すなわち、変数が格納するアドレスは、変数の有効バイト整列値の整数倍である.
address%最終有効バイト整列値=0;
二:いくつかのバイトの位置合わせ値についての説明
1変数の自己バイト整列値
1.1単純型変数:
char型データの場合、自己整列値は1、short型の場合は2、int、float、double型の場合、自己整列値は4、単位バイトです.
1.2構造タイプまたは連合タイプ:
自己バイト整列値のサイズは、メンバーの最大基本タイプに必要な有効バイト整列値です.
2コンパイラに必要なバイトの位置合わせ:
コンパイラ設定に必要なバイト位置合わせ値
3最終的に有効なバイト整列値:自身のバイト整列値とコンパイラが要求するバイト整列値の中で小さいものを取ります.
私のコンパイラ環境では、デフォルトでは4バイトの位置合わせが要求されています.上記の方法を最終的に表項目に並べて、より直感的に表すことができます.以下の表に示します.
 
char
short
int
double
float
自己整列値
1
2
4
8
4
コンパイラには値の位置合わせが必要です
4
4
4
4
4
有効な位置合わせ値
1
2
4
4
4
上記の表項目のルールは、単純なタイプ変数にも適しており、構造タイプ、連合タイプにも適しています.
4構造タイプの場合、連合タイプ計算でバイト数が大きい場合は、次のルールに従います.
4.1構造タイプ:
まず、構造内のすべての変数バイトの位置合わせが最後に、構造タイプ全体の位置合わせを保証する必要があります(ルール1.2を参照してください).
4.2連結タイプ:
まず、連合内で最大バイト数を占める変数バイトの位置合わせが要求され、最後に、連合タイプ全体の位置合わせが保証される(ルール1.2参照).例3:
   
例1:
struct data1{
 
              charc1;
              charc2[2];
};
sizeof(struct data1) = 3;
 
説明:data 1が0 x 0000アドレスから格納されると仮定します.この例ではバイト整列が指定されていません.GCCのデフォルト状態では4バイト整列で、最初の変数c 1、自己バイト整列値が1で、コンパイラが要求するバイト整列値より小さいので、有効整列値は1で、格納先は0 x 0000%1=0になります.2番目のメンバーは配列で、配列の整列が必要な場合、配列内の各メンバーは整列し、メンバーはcharタイプで、c 1と同じです.したがって、c 2の格納アドレスは0 x 001%1=0であり、最後にdata 1の位置合わせが要求される.
例2:
struct B{        char b;        int a;        short c;};Bはアドレス空間0 x 0000から排出を開始するものとする.この例では、指定した位置合わせ値は定義されていません.筆者の環境では、この値のデフォルトは4です.第1のメンバ変数bの自己整列値は1である、指定またはデフォルトの指定整列値4よりも小さいため、その有効整列値は1であるため、その格納アドレス0 x 0000が0 x 0000%1=0に該当する.2番目のメンバ変数aは、自身の整列値が4であるため、有効整列値も4であるため、先頭アドレスが0 x 004から0 x 007の4つの連続するバイト空間にしか格納できず、0 x 004%4=0をレビューし、1番目の変数に近い.3番目の変数cは、自己整列値が2であるため、有効整列値も2であり、0 x 008~0 x 009の2バイト空間に格納でき、0 x 008%2=0に適合する.したがって、0 x 0000から0 x 009まではBコンテンツが格納されます.また、データ構造Bの自己整列値は、その変数の中で最大整列値(ここではb)であるので4であるため、構造体の有効整列値も4である.構造体の丸みの要求に応じて、0 x 0009から0 x 0000=10バイト、(10+2)%4=0である.したがって、0 x 0000 A~0 x 000 Bも構造体Bに占有される.したがって、Bは0 x 0000から0 x 000 Bまで12バイトあり、sizeof(struct B)=12である.実際には、この1つだけでバイトが整列している場合、その先頭アドレスは0であるため、整列しているに違いありません.後に2バイトを追加するのは、コンパイラが構造配列のアクセス効率を実現するために、構造Bの配列を定義した場合、最初の構造開始アドレスは0で問題ありませんが、2番目の構造は?配列の定義に従って、配列の中のすべての要素は隣接していて、もし私たちが構造の大きさを4の整数倍に補充しなければ、次の構造の開始アドレスは0 x 0000 Aで、これは明らかに構造のアドレスの位置合わせを満たすことができなくて、だから私たちは構造を有効な位置合わせの大きさの整数倍に補充します.例えば、char型データの場合、自己整列値は1、short型の場合は2、int、float、double型の場合、自己整列値は4であり、これらの既存型の自己整列値も配列に基づいて考慮されるが、これらのタイプの長さが既知であるため、自己整列値も既知である
上記の方法があって、client端構造体の大きさを計算します.
sizeof(union snmp_data) = 100
サービス側:sizeof(union snmp_data)=104
リファレンス:
クリックしてリンクを開く
クリックしてリンクを開く
議論を歓迎し、誤りを指摘し、共に進歩する.