web-dev-qa-db-ja.com

Cの「パック」構造とは何ですか?

Microchip C30コンパイラ用に作成されたCコードをいくつか使用しますが、次のように定義された構造体をよく見ます。

typedef struct __attribute__((__packed__)) 
{
    IP_ADDR     MyIPAddr;               // IP address
    IP_ADDR     MyMask;                 // Subnet mask
    IP_ADDR     MyGateway;              // Default Gateway
        // etc...
} APP_CONFIG;

Packはどういう意味ですか?

31
PICyourBrain

構造が定義されると、コンパイラーはパディング(実際のデータのないスペース)を追加できるため、メンバーはCPUからアクセスしやすいアドレス境界に分類されます。

たとえば、32ビットCPUでは、効率的にアクセス(読み書き)するために、32ビットメンバーは4バイトの倍数のアドレスから開始する必要があります。次の構造定義は、2番目のメンバーが適切なアドレス境界に入るように、両方のメンバー間に16ビットのパディングを追加します。

struct S {
    int16_t member1;
    int32_t member2;
};

32ビットアーキテクチャの上記の構造のメモリ内の構造は( = padding)です。

+---------+---------+
| m1 |~~~~|   m2    |
+---------+---------+

構造体がパックされている場合、これらのパディングは挿入されません。コンパイラーは、整列されていないデータメンバーを抽出し、それらに書き込むために、より多くのコード(実行速度が遅い)を生成する必要があります。

同じ構造をパックすると、次のようにメモリに表示されます。

+---------+---------+
| m1 |   m2    |~~~~
+---------+---------+
61
Juliano

これは、structのメンバー間にパディングを追加しないようにコンパイラーに指示します。

たとえば このページ を参照してください。

6
NPE

_attribute__((__packed__))は、(おそらく)「パディングを挿入して処理を高速化しない」ことを意味し、「配置を保持するために配置を挿入しない」ことも意味します。

1
Vatine

構造体のパディングの概念を説明し、例を挙げて構造体をパックします。

次に、パッキングが必要な理由を見てみましょう。

パディング:

struct eg_struct
{
           unsigned char abc;
           unsigned int  xyz;
}

構造が16ビットアーキテクチャで上記のように宣言されている場合、変数abcにはアドレスが割り当てられます。次のアドレスは変数xyzに割り当てられず、代わりに1バイト追加され、次のアドレスが変数xyzに割り当てられます。

最終的に、構造は次のようになります。

struct eg_struct
{
           unsigned char abc;
           unsigned char paddedbytes[1];
           unsigned int  xyz;
}

パディングにより、メンバー変数のアドレスがマイクロコントローラーに簡単にアクセスできるようになります。欠点は、画像に入る余分な不要なバイトです。

パッキング:

同じ構造が属性「packed」を使用して宣言されている場合、変数abcの後に余分なバイトは追加されません。

パッキングが必要な1つの例を挙げましょう:

何らかの構造が保存されているEEPROMとインターフェースするマイクロコントローラーを考えてみましょう。

EEPROMに書き込む関数が次のようになるとします。

Write_EEPROM(EEPROM address, Ram address, Byte count);

これで、パッキングが行われない場合、余分な埋め込みバイトがEEPROM内のスペースを占有しますが、これは役に立ちません。

1
Babajan

明示的に呼び出されていないことの1つは、通常、パッキングが事前定義されたフィールド構造と一致するように行われることです。たとえば、ネットワークインターフェイスの低レベル層では、ネットワークに接続されたマシン間で一連のバイトが交換されます。データを受信した後、データを簡単に操作できるように、それを高レベルの構造にマップする必要があります。これは通常、パディングが不要なため、構造体がバイトに直接マップされるためです。

ネットワークデータの交換には、バイトエンディアンの問題も含まれます(つまり、ほとんどすべてのネットワークデータは、ソースマシンと宛先マシンのエンディアンに関係なくビッグエンディアン形式を使用します)。

さらに、一部のマシンcannot非境界整列アドレスのワイドデータにアクセスします。たとえば、Cortex-M0コアは非32ビット境界整列アドレスの32ビットデータにアクセスできないため、書き込みには注意が必要です。そのような場合のネットワークコード。