web-dev-qa-db-ja.com

uint16_tをchar [2]に変換して、ソケット(unix)経由で送信します

これには大まかに何かがあることを私は知っています。しかし、私の脳は痛く、私はこの仕事をするために何も見つけることができません...

UNIXソケットを介して16ビットの符号なし整数を送信しようとしています。そのためには、uint16_tを2つの文字に変換する必要があります。次に、接続のもう一方の端でそれらを読み込み、いずれかに変換し直す必要があります。 unsigned intまたはuint16_t、その時点では、2バイトまたは4バイトのどちらを使用するかは問題ではありません(64ビットを実行しているため、unsignedintを使用できません:)

私はCでこれをやっています

ありがとう

11
Michael Crook

マスクとシフトでバイトに分割してみませんか?

 uint16_t value = 12345;
 char lo = value & 0xFF;
 char hi = value >> 8;

(編集)

もう一方の端では、逆に組み立てます。

 uint16_t value = lo | uint16_t(hi) << 8;

頭のてっぺんから、そのキャストが必要かどうかわからない。

32
Steven Sudit
char* pUint16 = (char*)&u16;

つまり、uint16_tのアドレスをキャストします。

char c16[2];
uint16_t ui16 = 0xdead;
memcpy( c16, ui16, 2 );

c16には、u16の2バイトが含まれるようになりました。遠端では、単にプロセスを逆にすることができます。

char* pC16 = /*blah*/
uint16_t ui16;
memcpy( &ui16, pC16, 2 );

興味深いことに、memcpyの呼び出しがありますが、サイズが固定されているため、ほぼすべてのコンパイラがそれを最適化します。

Steven sudtが指摘しているように、ビッグエンディアンに問題が発生する可能性があります。これを回避するには、htons(Host-to-network short)関数を使用できます。

uint16_t ui16correct = htons( 0xdead );

遠端ではntohs(ネットワークからホストへのショート)を使用します

uint16_t ui16correct = ntohs( ui16 );

リトルエンディアンのマシンでは、これによりショートがビッグエンディアンに変換され、遠端でビッグエンディアンから変換されます。ビッグエンディアンマシンでは、2つの機能は何もしません。

もちろん、ネットワーク上の両方のマシンのアーキテクチャが同じエンディアンを使用していることをknowしている場合は、この手順を回避できます。

32ビット整数を処理するためにntohlとhtonlを検索します。ほとんどのプラットフォームは、64ビットのntohllとhtonllもサポートしています。

3
Goz

ビットマスクおよびシフト演算子 を使用する必要があるようです。

16ビットの数値を2つの8ビットの数値に分割するには:

  • ビット単位のAND演算子(Cでは&)を使用して下位8ビットをマスクし、上位8ビットがすべて0になるようにして、その結果を1つの文字に割り当てます。
  • 右シフト演算子(Cでは>>)を使用して、上位8ビットを右にシフトし、下位8ビットをすべて整数から押し出して、上位8ビットのみを残し、それを別の文字に割り当てます。

次に、これら2つの文字を接続を介して送信するときは、逆の操作を行います。以前は上位8ビットであったものを8ビット左にシフトし、ビット単位のORを使用して結合します。他の8ビットで。

2
dst2

基本的に、ソケットを介して2バイトを送信します。エンディアン、符号などに関係なく、ソケットが知る必要があるのはそれだけです... uint16を2バイトに分解し、ソケットを介して送信します。

char byte0 = u16 & 0xFF;
char byte1 = u16 >> 8;

もう一方の端では、反対の方法で変換を行います

1