【问题标题】:Encoding, decoding an integer to a char array将整数编码、解码为 char 数组
【发布时间】:2010-12-14 15:45:07
【问题描述】:

请注意,这不是家庭作业,我在开始这个新线程之前进行了搜索。我得到了Store an int in a char array?

我一直在寻找答案,但在上面的帖子中没有得到任何满意的答案。

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

这里是编码部分:

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,我只希望字节数组在第一个索引中有 ff int 第 0 个索引 aa 和bb 在第二个索引中。该怎么做?

snprinf 似乎不起作用,或者我可能遗漏了什么。

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

协议如下:

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

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

我希望我能澄清我的问题

【问题讨论】:

  • 感谢大家的及时帮助。我得到了它。我有点从 RFC 实现协议,因此需要所有这些信息。非常感谢:)

标签: c network-programming


【解决方案1】:

您存储为 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;

这使用大端字节顺序将变量a 序列化为byte_array 的前四个字节,这是许多网络协议的默认设置。

您可能还想在这里看到我的回答:question 1577161

【讨论】:

    【解决方案2】:

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

    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];
    

    【讨论】:

    • 呃——这个例子有很多错误。 1. 如果您要使用网络翻译例程(htonl() 和朋友),那么您必须传输整个变量。在 little-endian 机器上,此示例将切掉最低有效字节(在本例中为 0xaa)。 2. 如果您要通过自己剥离字节进行传输,则无需使用 htonl() - 该函数可确保二进制字节序格式与网络格式匹配。剥离字节时,您正在定义一种字节序格式。
    • 您说得对,我将第一个示例与 htonl 合并,但采用高位字节,另一个没有 htonl 但没有问题中要求的高位字节。我将编辑我的答案以删除对 htonl 的调用。
    【解决方案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;
    

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

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

    【讨论】:

      【解决方案4】:

      至少要便于移植,您应该考虑编码时可能存在不同的字节顺序。

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

      • 对于 RPC,请尝试“man rpc”
      • 对于 NASA IPC 看here

      【讨论】:

        【解决方案5】:

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

        与其重新发明轮子,不如使用 Google 的 Protocol Buffers 库来完成这项工作?更简单、更灵活、更高效。

        【讨论】:

          【解决方案6】:

          使用XDR (RFC 4506)。

          【讨论】:

            【解决方案7】:

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

            否则,您可以简单地执行类似...

            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;
            

            (您可以将msg + index 的概念替换为无符号字符指针,尽管这不太重要)。

            像这样使用 memcpy 可能会更慢,但也更具可读性。如有必要,您可以在 #define 或内联函数中实现 memcopy 克隆 - 毕竟这只是一个简短的赋值循环。

            【讨论】:

              【解决方案8】:

              你所拥有的不会以你拥有的方式发挥作用。例如, a 是 32 位,在您的示例中,您设置了高位,这意味着它不能使用您的 printf 语句放入 4 位数字。 (0xff00ffaa = 4278255530,多于 4 位)我相信它会溢出缓冲区。我相信 printf 会转换它并溢出该字段,但这取决于您的编译器/C 在没有足够缓冲区空间时如何实现 printf 函数。

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

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

              您的想法似乎不错,但仍需要一些工作。

              【讨论】:

                【解决方案9】:

                atoi 函数的使用仅在您期望解码的字符串是由您自己的代码构建并且不超过上述几行时才合理。即它只能在类似草图的代码中使用。

                否则,特别是在您的情况下,当数据从网络到达时,atoi 函数无法有意义地用于执行解码,因为它没有提供可用的错误处理机制并且绝对没有溢出保护(溢出时未定义的行为) .唯一可用于字符串到整数转换的函数是 strto... 组中的函数,在您的情况下为 strtol

                【讨论】:

                  【解决方案10】:

                  我已经看过这个页面一百万次了,我非常感谢所有其他帮助我的答案。这是我正在使用的存根,它与其他答案不同,因为它可以在 for 循环中使用:

                  void encode_int_as_char(int num, char *buf, int length){
                      int i;
                      for (i = 0; i < length; i++){
                          buf[i] = (char)(num >> ((8 * (length - i - 1)) & 0xFF));
                      }
                  }
                  
                  int decode_int_from_char(char *enc, int length){
                      int i, num, cur;
                  
                      num = 0;
                      for (i = 0; i < length; i++){
                          cur = (unsigned char) enc[i] << (8 * (length - i - 1));
                          num += (int) cur;
                      }
                  
                      return num;
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-04-06
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-10-08
                    • 1970-01-01
                    相关资源
                    最近更新 更多