将结构写入管道的正确方法是什么

时间:2012-12-17 00:01:57

标签: c linux

在linux,2.6.x上,给出以下结构

struct A
{
  int a;
  int b;
} ss;

将上述结构写入管道时我想到的两个选项是

  1. memcpy from& ss to sizeof(ss)
  2. 复制ss-> a,然后复制ss-> b
  3. 一个比另一个好吗?

2 个答案:

答案 0 :(得分:2)

没有“正确”的方式,但有些方法肯定比其他方法更好。

对于初学者来说,int的大小取决于机器,编译器和选项。您可能不希望您的network / ipc协议随之变化。其次,整数中字节的顺序可以随着相同的事情而变化。因此,首先定义整数的大小和顺序(endianess)。假设你使用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;
}

解码必须使用提供的字节并使用逻辑/算术运算重新组合整数。另一种可能性是使encode_int使用可变数量的字节(并编码它使用的数量),如果你期望大多数小整数和/或想要也处理64位平台。还有许多其他选项 - 主要的是不允许内存中表示的任意性来定义您的协议。

另请参阅ntohl,htonl,ntohs,htons标准函数。

聚苯乙烯。最后一次编辑 - 如果阅读器中整数的大小与编写器中的整数大小不同,则必须注意正确处理负整数。

答案 1 :(得分:0)

我完全同意DrC。

您的简单结构表明您只是在暗示您手头的问题。您需要考虑的是结构的内存布局,这可能会有很大的不同,具体取决于CPU,编译器及其sizeof(int)。考虑:

struct B {
    int a;
    char b;
    int c;
}

编译器将在sizeof(int)边界上对齐'c'。也就是说'b'和'之间会有一些填充。 'C'。如果sizeof(int)是2,那么只需要一个额外的字节就可以在int边界上启动'c'。如果sizeof(int)为4,就像在大多数32位处理器上一样,则需要三个填充字节。问题确实来自64位处理器。 sizeof(int)可以是四个或八个。

因此,对问题的简单回答是分别传输结构的每个元素,因为这样可以避免传输任何填充字节。但是如果你的管道的两端都同意sizeof(< data-type>)等于什么,以及int,long,long longs,float,double,...的字节顺序,那么你只会逃避这一点。

但是考虑到目前的网络带宽,我认为最好使用基于ASCII的传输协议(例如XML),除非有一个很好的理由。