我在C中有一个看起来像这样的结构:
typedef u_int8_t NN;
typedef u_int8_t X;
typedef int16_t S;
typedef u_int16_t U;
typedef char C;
typedef struct{
X test;
NN test2[2];
C test3[4];
U test4;
} Test;
Run Code Online (Sandbox Code Playgroud)
我已经将字段的结构和写入值声明如下:
Test t;
int t_buflen = sizeof(t);
memset( &t, 0, t_buflen);
t.test = 0xde;
t.test2[0]=0xad; t.test2[1]=0x00;
t.test3[0]=0xbe; t.test3[1]=0xef; t.test3[2]=0x00; t.test3[3]=0xde;
t.test4=0xdeca;
Run Code Online (Sandbox Code Playgroud)
我通过UDP将此结构发送到服务器.目前我在本地测试时工作正常,但是我现在需要将这个结构从我的little-endian机器发送到big-endian机器.我真的不确定怎么做.
我已经研究过使用htons但我不确定这是否适用于这种情况,因为它似乎只定义为unsigned ints16位或32位,如果我理解正确的话.
Jim*_*mbo 17
我认为这里可能存在两个问题,具体取决于您如何通过TCP发送此数据.
至于,你已经说过字节序是一个问题.当你提到使用htons和ntohs短裤时,你是对的.您也可以找到htonl它的相反用途.
Endianness与内存中多字节数据类型的字节排序有关.因此,对于单字节宽度的数据类型,您不必担心.在你的情况下是2字节数据,我猜你正在质疑.
要使用这些功能,您需要执行以下操作...
Sender:
-------
t.test = 0xde; // Does not need to be swapped
t.test2[0] = 0xad; ... // Does not need to be swapped
t.test3[0] = 0xbe; ... // Does not need to be swapped
t.test4 = htons(0xdeca); // Needs to be swapped
...
sendto(..., &t, ...);
Receiver:
---------
recvfrom(..., &t, ...);
t.test4 = ntohs(0xdeca); // Needs to be swapped
Run Code Online (Sandbox Code Playgroud)
使用htons()和ntohs()使用以太网字节排序...大端.因此,您的little-endian机器字节交换t.test4并且在收到大端机器时只使用该值读取(ntohs()有效地是noop).
下图将使这一点更清晰......

如果您不想使用该htons()函数及其变体,则可以在字节级别定义缓冲区格式.这个图表使这更清楚......

在这种情况下,您的代码可能看起来像
Sender:
-------
uint8_t buffer[SOME SIZE];
t.test = 0xde;
t.test2[0] = 0xad; ...
t.test3[0] = 0xbe; ...
t.test4 = 0xdeca;
buffer[0] = t.test;
buffer[1] = t.test2[0];
/// and so on, until...
buffer[7] = t.test4 & 0xff;
buffer[8] = (t.test4 >> 8) & 0xff;
...
sendto(..., buffer, ...);
Receiver:
---------
uint8_t buffer[SOME SIZE];
recvfrom(..., buffer, ...);
t.test = buffer[0];
t.test2[0] = buffer[1];
// and so on, until...
t.test4 = buffer[7] | (buffer[8] << 8);
Run Code Online (Sandbox Code Playgroud)
无论发送方和接收方的相应字节顺序如何,发送和接收代码都将起作用,因为缓冲区的字节布局是由两台机器上运行的程序定义和识别的.
但是,如果您以这种方式通过插座发送结构,您还应该注意下面的警告......
文章"数据对齐:拉直和向右飞"对于这个文章是一个很好的阅读...
您可能遇到的另一个问题是数据对齐.情况并非总是如此,即使在使用不同端序约定的机器之间,但仍然需要注意......
struct
{
uint8_t v1;
uint16_t v2;
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码位中,v2从结构开始的偏移量可以是1字节,2字节,4字节(或几乎任何东西).编译器不能重新排序结构中的成员,但它可以填充变量之间的距离.
可以说机器1有一个16位宽的数据总线.如果我们采用没有填充的结构,机器将不得不做两次提取v2.为什么?因为我们在h/w级别一次访问2个字节的内存.因此编译器可以像这样填充结构
struct
{
uint8_t v1;
uint8_t invisible_padding_created_by_compiler;
uint16_t v2;
}
Run Code Online (Sandbox Code Playgroud)
如果发送方和接收方在将数据打包到结构中的方式上有所不同,那么仅将结构作为二进制blob发送将导致问题.在这种情况下,您可能必须在发送之前手动将变量打包到字节流/缓冲区中.这通常是最安全的方式.