0

複雑な構造体があるとします

struct icmphdr
{
     u_int8_t type;
     u_int8_t code;
     u_int16_t checksum;

    /* Parts of the packet below don’t have to appear */
    union
    {
        struct
        {
            u_int16_t id;
            u_int16_t sequence;

            // Type of ICMP message
            // Packet code
           // Datagram checksum
        } echo;

        u_int32_t gateway;

        struct
        {
            u_int16_t __unused;
            u_int16_t mtu;
        } frag;


   } un;

}; 

そして

char buf[SIZE];//for some integer SIZE

このキャストの意味と興味は何ですか?

ip=(struct icmphdr*)buf; //ip was formerly defined as some struct iphdr *ip;
4

2 に答える 2

1

コードの背後にある可能性のあるシナリオは次のとおりです。

プログラマーは、プログラミングを容易にし、コードの可読性を向上させるために、データ プロトコルを作成し、さまざまな内容を構造体として表現したいと考えていました。

基礎となる API は、おそらくバイト単位でのデータ転送のみを許可します。これは、構造体を「バイトのチャンク」として渡す必要があることを意味します。特定のコードはレシーバーのように見えます。生のバイトのチャンクがあり、それらのバイトのデータが構造体に対応していると述べています。

形式的にも理論的にも、C 標準では、異なるデータ型へのポインター間でキャストしたときに何が起こるかを定義していません。理論的には、あなたがそうすれば何でも起こり得ます。しかし、実際/現実の世界では、データの構造について何らかの保証がある限り、そのようなキャストは明確に定義されています。

ここで問題が発生する可能性があります。多くのコンピューターにはアラインメント要件があります。つまり、コンパイラーは構造体/共用体内の任意の場所にいわゆるパディング バイトを自由に挿入できます。これらの埋め込みバイトは、2 つのコンパイル間で必ずしも同じであるとは限りません。また、2 つの異なるシステム間で同じであるとは限りません。

したがって、送信者と受信者の両方でパディングが有効になっていないか、同じパディングが設定されていることを確認する必要があります。そうしないと、構造体/共用体を使用できず、プログラムがクラッシュして書き込みが発生します。

構造体のパディングが有効になっていないことを確認する手っ取り早い方法は#pragma pack 1、多くのコンパイラで一般的にサポートされている非標準などのコンパイラ オプションを使用することです。

専門的で移植可能な方法は、コンパイル時のアサートを追加して、構造体のサイズが実際に意図したとおりであることを確認することです。C11では、次のようになります

static_assert(sizeof(struct icmphdr) == 
                (sizeof(uint8_t) + 
                 sizeof(uint8_t) + ... /* all individual members' types */ ), 
              "Error: padding detected");

コンパイラが をサポートしていない場合、static_assertさまざまなマクロやランタイムで同様のことを実現する方法がいくつかありますassert()

于 2013-05-13T15:12:39.243 に答える