Linux 2.6.x では、次の構造体が与えられます
struct A
{
int a;
int b;
} ss;
上記の構造体をパイプに書くために頭に浮かぶ2つのオプションは
- &ss から sizeof(ss) への memcpy
- ss->a をコピーし、ss->b をコピー
一方が他方よりも優れていますか?
「正しい」方法はありませんが、いくつかの方法は他の方法よりも確実に優れています。
まず、int のサイズは、マシン、コンパイラ、およびオプションに依存します。おそらく、ネットワーク/ipc プロトコルをそれらに合わせて変更したくないでしょう。第二に、整数のバイトの順序は、同じことで異なる場合があります。したがって、最初に整数のサイズと順序 (エンディアン) を定義します。32 ビットのビッグ エンディアンを使用するとします。次に、バイトのコピーやオーバーレイではなく、数値/論理演算を使用してこれらのバイトを抽出します。最後に、実際にストリームでサイズの仮定をエンコードしたい場合があります。
いくつかのサンプル コード。各関数は、パラメーターを提供されたバッファーにエンコードし、バッファーで使用されている文字数を返します。
int encode_int(int v, unsigned char *s) {
s[0] = (v>>24) & 0xff;
s[1] = (v>>16) & 0xff;
s[2] = (v>>8) & 0xff;
s[3] = v & 0xff;
return 4;
}
int encode_A(struct A *a, unsigned char *s) {
int offset = 0;
s[offset++] = 4; // Size of ints - really belongs in a global header or in encode_int
offset += encode_int(a->a, s+offset);
offset += encode_int(a->b, s+offset);
return offset;
}
デコードでは、提供されたバイトを取得し、論理/算術演算を使用して整数を再構築する必要があります。もう 1 つの可能性は、encode_int が可変バイト数を使用するようにする (そして使用したバイト数をエンコードする) ことです。他にも多くのオプションがあります-主なことは、メモリ内表現の恣意性がプロトコルを定義することを許可しないことです。
ntohl、htonl、ntohs、htons 標準関数も参照してください。
Ps。最後の編集 - リーダーの整数のサイズがライターの整数のサイズと同じでない場合、負の整数を正しく処理するように注意する必要があります。
私はDrCに完全に同意します。
あなたの単純な構造は、目前の問題をほのめかしているだけであることを示唆しています。考える必要があるのは、構造体のメモリ レイアウトです。これは、CPU、コンパイラ、および sizeof(int) によって大きく異なる可能性があります。検討:
struct B {
int a;
char b;
int c;
}
コンパイラは、'c' を sizeof(int) 境界に揃えます。つまり、'b' と 'c' の間にいくらかのパディングがあるということです。sizeof(int) が 2 の場合、'c' を int 境界で開始するために必要な追加バイトは 1 つだけです。ほとんどの 32 ビット プロセッサのように sizeof(int) が 4 の場合、3 つのパディング バイトが必要です。この問題は、実際には 64 ビット プロセッサで発生します。sizeof(int) は 4 または 8 です。
したがって、質問に対する単純な答えは、構造体の各要素を個別に送信することです。これにより、パディング バイトの送信が回避されます。ただし、パイプの両端が sizeof(<data-type>) と等しいものと、int、long、long long、float、double などのバイト順の両方に同意する場合にのみ、これを回避できます。
しかし、最近のネットワーク帯域幅を考えると、よほどの理由がない限り、ASCII ベースの転送プロトコル (XML など) を使用するのが最善だと思います。