编码,将整数解码为char数组

请注意,这不是作业,我在开始这个新主题之前进行了搜索。 我在char数组中得到了一个int?

我正在寻找答案,但在上面的post中没有得到任何满意的答案。

这是我的要求:我想在一个字节数组中编码我的数据(比如一个整数),然后通过网络传输,然后在另一端解码并处理它。

这是编码部分:

const int MAX=5; uint32_t a = 0xff00ffaa; char byte_array[1024]; // this is the array to be transferred over the network char buff[MAX]=""; sprintf(buff,"%4d",a); memcpy(byte_array,buff,4); // fill remaining stuff in the byte array and send it over the network 

这是解码部分:

 const int MAX=5; char buff[MAX]=""; strncat(buff,byte_array,4) int i=atoi(buff); // Work with i 

这是我的问题:

1)上述代码是否可移植? 我猜是(请纠正我)

2)现在,我希望用3个字节(但整数大小为4)对字节数组进行编码,即假设整数存储0x00ffaabb,我只希望字节数组在第1个索引中具有ff int第0个索引aa,在bb中使用bb第二指数。 怎么做?

snprinf似乎不起作用或可能是我错过了什么。

实施任何网络协议的人都可以轻松帮助我。 我想,解码逻辑仍然有用。 ( strncat(buff,byte_array,3)后跟atoi函数调用)。

这是协议所说的内容:

     -------- + -------- + -------- + -------- + -------------- ----------------
     |版本|  3字节长度| 剩下的东西
     -------- + -------- + -------- + -------- + -------------- ----------------

版本为1个字节,后跟消息的3个字节长度。

我希望我能澄清我的问题

您将以ASCII格式存储,您应该在其中存储字节。

编码应该类似于:

 uint32_t a = 0xff00ffaa; unsigned char byte_array[1024]; 

请注意我如何使目标数组无符号,以指示它是“原始字节”,而不是实际字符。

 byte_array[0] = a >> 24; byte_array[1] = a >> 16; byte_array[2] = a >> 8; byte_array[3] = a >> 0; 

这使用big-endian字节排序将变量a序列化为byte_array的前四个字节,这是许多网络协议的默认排序。

您可能还想在此处查看我的答案: 问题1577161 。

1)由于你使用一系列字符进行传输,它有点工作,我会亲自使用二进制协议。 如果你可以使用你的变量的4个字节,我会看看htonl / ntohl函数(它们几乎在每个unix和windows上,因为w2k),否则见下文

2)使用二进制协议,编码即可

 uint32_t a = 0xff00ffaa; char byte_array[1024]; // this is the array to be transferred over the network // leave byte_array[0] for version byte // leave the high order byte in a since you want only the 3 lowest byte_array[1] = (char)((a & 0x00FF0000)>>16); byte_array[2] = (char)((a & 0x0000FF00)>>8); byte_array[3] = (char)(a & 0x000000FF); 

和解码将是

 uint32_t a = 0; a |= byte_array[1]<<16; a |= byte_array[2]<<8; a |= byte_array[3]; 

你正在做什么将是一种工作。 您没有传输数据的字节 – 您正在传输数据的数值。 因此,对于您要发送的数据,大小为5的缓冲区太小(0xFF00FFAA的数值为4278255530 – 10个字节)。

要传输字节,您需要执行以下操作(假设小端):

编码:

 char array[1024]; // outgoing network data int next = 0; array[next++] = value & 0xFF; array[next++] = (value >> 8) & 0xFF; array[next++] = (value >> 16) & 0xFF; array[next++] = (value >> 24) & 0xFF; 

这些语句剥离了值的字节,并将它们分配给数组中的连续值。

解码:

 char array[1024]; // incoming network data int next = 0; value = 0; value |= (int)*((unsigned char*)array)[next++]; value |= (int)*((unsigned char*)array)[next++] << 8; value |= (int)*((unsigned char*)array)[next++] << 16; value |= (int)*((unsigned char*)array)[next++] << 24; 

这些语句将字节拉出数组并将它们推回到值中。

如果您想尝试优化网络格式而不是传输字节,则可以消除一些数据。 但请记住,您的发送方和接收方需要彼此了解所期望的内容 - 因此需要对所传递的数据元素的类型或长度进行一些沟通。

至少要是可移植的,你应该考虑编码时可能的不同字节顺序。

您真的需要实现新的网络消息传递协议吗? NASA IPC或Sun RPC不适合你吗? 它们都足够稳定,NASA更容易启动,RPC看起来更广泛(是的,它已经可以使用,库可用于大多数流行的系统)。

  • 对于RPC尝试’man rpc’
  • 对于NASA IPC,请看这里

也许您需要使用现有协议来完成这项工作,在这种情况下,请忽略我的答案。

而不是在这里重新发明轮子,为什么不使用谷歌的协议缓冲库来完成这项工作? 更简单,更灵活,更高效。

使用XDR ( RFC 4506 )。

你拥有的东西不会以你拥有它的方式运作。 例如,a是32位,在您的示例中,您设置了高位,这意味着它不能与printf语句匹配为4位数。 (0xff00ffaa = 4278255530,超过4位)我相信它会溢出缓冲区。 我相信printf会转换它并溢出字段,但它取决于当没有足够的缓冲区空间时编译器/ C如何实现printf函数。

对于您拥有的printf语句,您传入的最大值对于4个字符将是9999。 同样,在使用3字节长度字段传输数据的示例中,最大长度为999.理论上,如果长度加1,但已声明的缓冲区为1024,则长度可能为1000。您需要的最大缓冲区长度为1004字节长。

使用ASCII字符确实可以使消息/数据在整个系统中可移植,但这是以使用更多带宽/空间和编程时间和精力来转换ASCII来传输数据为代价的。

看起来你有一个好主意,但它仍然需要一些工作。

最好使用一些现有的工具。 如果你不能 – 你关心字节顺序(即这是一个跨平台协议吗?)

否则,你可以简单地做…

 unsigned char msg[1024]; int writeIndex = 0; [...] int mynum = 12345; memcpy(msg + writeIndex , &mynum, sizeof mynum); writeIndex += sizeof mynum; 

并解码

 //[...] also declare readIndex; memcopy(&mynum, msg + readIndex, sizeof mynum); readIndex += sizeof mynum; 

(你可以用无符号的char指针替换msg + index的概念,尽管这不太重要)。

像这样使用memcpy可能会更慢,但也更具可读性。 如果有必要,你可以在#define或inline函数中实现memcopy clone – 毕竟它只是一个简短的赋值循环。

只有当您希望解码的字符串是由您自己的代码构建而且上面几行以外,才能使用atoi函数。 即它只能用于类似草图的代码。

否则,特别是在你的情况下,当数据从网络到达时, atoi函数不能有意义地用于执行解码,因为它没有提供可用的error handling机制,并且绝对没有溢出保护(溢出时的未定义行为)。 唯一可以有意义地用于字符串到整数转换的函数是来自strto... group的strtol在你的情况下是strtol