2

htonl()とhtos()を使用して、メッセージをホストバイトオーダーからネットワークオーダーに変換したいと思います。このメッセージには、構造、列挙型、共用体、および共用体内の共用体のような複雑に定義されたデータ型がいくつかあります。

  1. すべての構造体のメンバー、およびマルチバイトであるユニオンのメンバーを含むメンバーのメンバーをhtonlする必要がありますか?
  2. 組合の場合、最大のものを翻訳することはできますか?
  3. 列挙型の場合、私はそれを同じくらい長く翻訳できますか?
  4. メッセージの送信と受信の両方にhtonl(s)を使用する1つの関数を作成できますか?または、同じメッセージを受信するためにntohl(s)を使用している別のメッセージを考え出す必要がありますか?

構造

typedef struct {
    unsigned short un1_s;
    unsigned char  un1_c;

    union {
        unsigned short un1_u_s;        
        unsigned long  un1_u_l;    
    }u;
}UN1;

typedef struct {
    unsigned short    un2_s1;
    unsigned short    un2_s2;
} UN2;

typedef enum {
    ONE,
    TWO,
    TRHEE,
    FOUR
} ENUM_ID;

typedef struct {
    unsigned short  s_sid;
    unsigned int    i_sid;
    unsigned char   u_char;
    ENUM_ID         i_enum;

    union {
            UN1     un1;
            UN2     un2;
    }               u;
} MSG;

コード

void msgTranslate (MSG* in_msg, MSG* out_msg){

/* ignore the code validating pointer ... */

*out_msg = *in_msg;

#ifdef LITLE_ENDIAN

/* translating messeage */
out_msg->s_sid = htons( in_msg->s_sid );  /* short */
out_msg->i_sid = htonl( in_msg->i_sid );  /* int */

/* Can I simply leave out_msg->u_char not to translate, 
 * because it is a single byte? */

out_msg->i_enum = htonl(in_msg->i_enum);  
/* Can I simply translate a enum this way,? */

/* For an union whose 1st member is largest one in size than 
 * others, can I just translate the 1st one, 
 * leaving the others not to convert? */

out_msg->u.un1.un1_s = htons(in_msg->u.un1.un1_s);  


/* for out_msg->u_char, can I simply leave it 
 * not to be converted, because it is a single byte? */

/* for an union whose 2nd member is largest one, 
 * can I just convert the 2nd one, leaving others 
 * not to be converted? */

out_msg->u.un1.u.un1_u_s = htos(in_msg->u.un1.u.un1_u_s ); /* short */

/* As above question, the following line can be removed? 
 * just because the u.un1.u.un2_u_i is smaller 
 * than u.un1.u.un1 in size ? */

out_msg->u.un1.u.un2_u_i = htol(in_msg->u.un1.u.un2_u_l );  /* long */

/* Since un1 is largest than un2, the coding translation un2 can be ignored? */
    ...

#endif

    return;
}
4

2 に答える 2

3
  1. すべてのマルチバイトタイプを適切にマップする必要があります。

  2. ユニオンの場合、ユニオンの「アクティブな」要素を特定し、通常のルールに従ってマップする必要があります。また、さまざまな可能性のどれが送信されたかを受信コードに伝える「ディスクリミネーター」を提供する必要がある場合もあります。

  3. 列挙型の場合、そのようなすべての値をaとして扱い、longそれに応じてエンコードおよびデコードすることを決定できます。または、各列挙型を個別に処理し、サイズに応じて各タイプを処理することもできます(理論的には、列挙型が異なればサイズも異なります)。

  4. それはあなたが次に実際に何をしようとしているのかに少し依存します。ネットワークを介して送信するためにデータをパッケージ化する場合、受信操作と送信操作はかなり異なります。htonl()メモリ内の構造体のビットを反転するだけの場合、ほとんどのシステムで、関数をの結果に適用した結果htonl()は、最初に考えた数であることがわかるでしょう。マップされた(反転された)構造体のすべてのバイトのバイナリコピーを実行することを計画している場合は、おそらく正しく実行されていません。

ほとんどのもっともらしいシステムでは、データ構造にさまざまなパディングホールがあることに注意してください。構造体UN1では、32ビットシステムの場合、ほぼ確実に、un1_cと次のユニオンの間にパディングバイトがあります。u64ビットシステムの場合は、おそらく5バイトのパディングがあります。同様に、MSG構造体では、おそらく、の後に2バイト、。の後s_sidにさらに3バイトがありますu_charenum(および32ビットマシンと64ビットマシンのどちらを使用しているか)のサイズによっては、の後に1〜7バイトのパディングがある場合がありますi_enum

データ型にプラットフォームに依存しないサイズがないため、32ビットと64ビットのUnixシステム間で確実に相互作用することはできないことに注意してください。sizeof(long) == 4システムがすべてWindowsの場合、 32ビットと64ビットの両方のWindowsを使用しているので、問題はありません。ただし、基本的にすべての64ビットのUnixバリアントでは、sizeof(long) == 8。したがって、クロスプラットフォームでの作業が問題になる場合は、これらのサイズとパディングについて心配する必要があります。や<inttypes.h>などのヘッダーのタイプを調べます。uint16_tuint32_t

すべてのホストで同じパッキングを実行し、さまざまな値のバイトを文字バッファー内の適切な場所に慎重にコピーする必要があります。これは、ネットワーク経由で送信され、逆コーディングによって解凍されます。

また、GoogleのProtocolBuffersがあなたに代わって賢明に機能するかどうかも確認してください。それはあなたにかなりの痛みと悲しみを救うかもしれません。

于 2012-09-18T04:04:44.933 に答える
2
  1. 1バイトより長い整数(short、int、long、long long)をエンディアンフリップする必要があります。
  2. いいえ。以下を参照してください。
  3. enumプラットフォームに応じて、番号は任意のサイズになる可能性があります( Cでの列挙型のサイズは何ですか?を参照)。
  4. 現実的には、この変換をすべて実行しようとするのではなく、プロトコルバッファなどを使用する必要があります...

ユニオンは扱いにくいです。たとえば、値0x1234をビッグエンディアンshortののに格納するとします。union {short; long;}次に、12 34 00 00shortがユニオンの下位2バイトを占めるため、ユニオンにはバイトが含まれます。をエンディアンフリップするlongと、が得られ00 00 34 12short0x0000が生成されます。をエンディアンフリップするshortと、が得られ34 12 00 00ます。どちらが正しいと思うかはわかりませんが、問題があることは明らかです。

shortそのようなユニオンに2つのsがあり、1つshortは低いハーフワードで、もう1つは高いハーフワードであるのがより一般的です。どちらがエンディアンに依存しますが、あなたはできます

union {
    #ifdef LITTLE_ENDIAN
    uint16_t s_lo, s_hi;
    #else
    uint16_t s_hi, s_lo;
    #endif
    uint32_t l;
};
于 2012-09-18T03:33:25.737 に答える