简体   繁体   English

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

[英]Encoding, decoding an integer to a char array

Please note that this is not homework and i did search before starting this new thread. 请注意,这不是家庭作业,我在开始此新线程之前进行过搜索。 I got Store an int in a char array? 将int存储在char数组中?

I was looking for an answer but didn't get any satisfactory answer in the above thread. 我在寻找答案,但是在上述线程中没有得到满意的答案。

Here's my requirement: I want to encode my data(say an integer) in a byte array and then transfer over the network and then decode at the other end and process it. 这是我的要求:我想将我的数据(例如整数)编码为字节数组,然后通过网络传输,然后在另一端解码并处理它。

Here's the encoding part: 这是编码部分:

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

Here's the decoding part: 这是解码部分:

const int MAX=5;
char buff[MAX]="";
strncat(buff,byte_array,4)

int i=atoi(buff);
// Work with i

Here are my questions : 这是我的问题:

1) Is the above code portable? 1)上面的代码可移植吗? I guess it is( please correct me) 我想是(请纠正我)

2) Now, I wish to encode the byte array with 3 bytes (but the integer size is 4) ie say the integer stores 0x00ffaabb and i just want the byte array to have ff int 0th index aa in the 1st index and bb in the 2nd index. 2)现在,我希望将字节数组编码为3个字节(但整数大小为4),即说整数存储0x00ffaabb,而我只希望字节数组在第1个索引中具有ff int 0th个索引aa,在第一个索引中具有bb第二索引。 How to do that? 怎么做?

snprinf doesn't seem to work or may be i am missing something. snprinf似乎不起作用,或者可能是我缺少了一些东西。

A person who has implemented any network protocol can easily help me out. 实施任何网络协议的人都可以轻松帮助我。 Decoding logic would still work i guess. 我猜解码逻辑仍然可以工作。 ( strncat(buff,byte_array,3) followed by atoi function call). strncat(buff,byte_array,3)后跟atoi函数调用)。

Here's what the protocol says : 协议说明如下:

--------+--------+--------+--------+------------------------------
    |Version|   3       byte    length |  Remaining stuff
    --------+--------+--------+--------+------------------------------

Version is 1 byte, followed by 3 byte length of the message. 版本为1字节,后跟消息的3字节长度。

I hope I could clarify my problem 我希望我可以澄清我的问题

You're storing as ASCII, where you should be storing the bytes themselves. 您将以ASCII格式存储,应该在其中存储字节本身。

The encoding should be something like: 编码应类似于:

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

Notice how I made your target array unsigned, to indicate that it's "raw bytes", and not actually characters. 注意我如何使目标数组无符号,以表明它是“原始字节”,而不是字符。

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

This serializes the variable a into the four first bytes of byte_array using big-endian byte ordering, which is sort of the default for many network protocols. 这使用大端字节顺序将变量a序列化为byte_array的前四个字节,这是许多网络协议的默认设置。

You may also want to see my answer here: question 1577161 . 您可能还想在这里看到我的答案: 问题1577161

1) it sort of work since you use an array of characters for the transportation, I would use a binary protocol personally. 1)这是一种工作,因为您使用字符数组进行运输,所以我个人会使用二进制协议。 If you can use the 4 bytes of your variable, I would take a look to htonl/ntohl functions (they are on virtually every unix and on windows since w2k), else see below 如果您可以使用变量的4个字节,那么我来看看htonl / ntohl函数(自w2k以来,它们实际上在每个unix和Windows上),否则请参见下文

2) with a binary protocol, encoding would be 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);

and decoding would be 和解码将是

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

What you're doing will sort-of work. 您正在做的事情将完成一些工作。 You're not transferring the bytes of the data - you're transferring the numeric value of the data. 您不是在传输数据的字节,而是在传输数据的数值。 As a result a buffer of size 5 is way too small for the data you're sending (0xFF00FFAA has a numeric value of 4278255530 - 10 bytes). 因此,对于要发送的数据,大小为5的缓冲区太小了(0xFF00FFAA的数值为4278255530-10个字节)。

To transfer the bytes you need to do something like the following (assumes little endian): 要传输字节,您需要执行以下操作(假设使用小字节序):

Encode: 编码:

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;

These statements strip off the bytes of the value and assign them to successive values in your array. 这些语句剥离值的字节,并将其分配给数组中的后续值。

Decode: 解码:

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;

These statements pull the bytes out of the array and push them back into the value. 这些语句将字节从数组中拉出,然后将其推回值中。

If you want to try to optimize your network format and not transfer bytes you can eliminate some of the data. 如果要尝试优化网络格式而不传输字节,则可以消除一些数据。 But remember that your sender and receiver need to know from each other what to expect - so there needs to be some communication of what the type or length of data elements being passed is. 但是请记住,您的发送方和接收方需要彼此了解期望的内容-因此需要进行某种通信,以传递要传递的数据元素的类型或长度。

At least to be portable you should think about possible different byte order on encoding. 至少为了便于移植,您应该考虑编码上可能的不同字节顺序。

Do you really need to implement new networking messaging protocol? 您是否真的需要实现新的网络消息传递协议? Don't NASA IPC or Sun RPC suit you? NASA IPC或Sun RPC不适合您吗? They both are stable enough, NASA is simpler to startup, RPC seems available more widely (yes, it is ready to use and library is available for most popular systems). 它们都足够稳定,NASA更易于启动,RPC似乎更广泛可用(是的,它可以立即使用,并且库可用于大多数流行的系统)。

  • For RPC try 'man rpc' 对于RPC,请尝试使用“ man rpc”
  • For NASA IPC look here 对于NASA IPC,请点击此处

Maybe you need to make this work with an existing protocol, in which case, ignore my answer. 也许您需要使用现有协议来完成此工作,在这种情况下,请忽略我的回答。

Rather than reinvent the wheel here, why don't you use Google's Protocol Buffers library to do this job? 您为什么不使用Google的Protocol Buffers库来完成这项工作,而不是在这里重新发明轮子? Simpler, more flexible and very efficient. 更简单,更灵活且非常高效。

使用XDRRFC 4506 )。

What you have will not work in the manner in which you have it. 您所拥有的将无法以您拥有的方式工作。 For example, a is 32 bit and in your example you the high order bits set, which means it cannot fit into a 4 digit number with your printf statement. 例如,a是32位,而在您的示例中您设置了高位,这意味着它不能与您的printf语句一起容纳4位数字。 (0xff00ffaa = 4278255530, which is more then 4 digits) I believe it will overflow the buffer. (0xff00ffaa = 4278255530,大于4位)我相信它将使缓冲区溢出。 I believe printf will convert it and overflow the field, but it depend on how your compiler/C implements the printf function when there is not enough buffer space. 我相信printf会转换它并溢出该字段,但这取决于您的编译器/ C在缓冲区空间不足时如何实现printf函数。

For the printf statement you have, the maximum value you could pass in would be 9999 for 4 characters. 对于您拥有的printf语句,您可以传入的最大值为4个字符的9999。 Likewise, in you example of transferring the data with the 3 byte length field, you would have a maximum length of 999. In theory your length could be 1000, if you added 1 to the length, but the buffer you have declared, is 1024 where the maximum buffer length you would need would be 1004 bytes long. 同样,在使用3个字节的长度字段传输数据的示例中,最大长度为999。理论上,如果您将长度加1,则长度可以为1000,但是声明的缓冲区为1024您需要的最大缓冲区长度为1004个字节。

Using ASCII characters does make messages/data portable across the system, but it is at the expense of using more bandwidth/space and programming time and effort to convert back and forth from ASCII to transfer the data. 使用ASCII字符确实使消息/数据可在整个系统中移植,但是这是以使用更多带宽/空间以及编程时间和精力来从ASCII来回转换以传输数据为代价的。

It seems like you have a good idea, but it still needs a bit of work. 看来您有个好主意,但仍然需要一些工作。

It's probably best to use some existing tool. 最好使用一些现有工具。 If you can't - do you care about endianness (ie is this a cross platform protocol?) 如果不能-您是否关心字节顺序(即,这是跨平台协议吗?)

Otherwise, you can simply do something like... 否则,您可以简单地做类似...

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

and to decode 并解码

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

(you could replace the notion of msg + index with an unsigned char pointer, though this is unlikely to matter). (您可以用无符号的char指针替换msg + index的概念,尽管这不太重要)。

Using memcpy like this is liable to be slower, but also more readable. 像这样使用memcpy可能会比较慢,但也更具可读性。 If necessary, you could implement a memcopy clone in a #define or inline function - it's just a short loop of assignments, after all. 如有必要,您可以在#define或内联函数中实现memcopy克隆-毕竟,这只是一小段分配。

The use of atoi function is only justified when the string that you are expecting to decode was build by your own code and no further than a couple of lines above. 仅当您希望解码的字符串是由您自己的代码构建且仅在上面的两行之内完成时,才可以使用atoi函数。 Ie it is only usable in sketch-like code. 即,它仅在类似草图的代码中可用。

Otherwise, especially in your case, when the data arrives from the network, atoi function cannot be meaningfully used to perform decoding, since it provides no usable error handling mechanism and absolutely no protection from overflow (undefined behavior on overflow). 否则,特别是在您的情况下,当数据从网络到达时,无法有效地使用atoi函数执行解码,因为它没有提供可用的错误处理机制并且绝对没有针对溢出的保护(溢出时未定义的行为)。 The only function that can be meanigfully used for string-to-integer conversion is a function from the strto... group, strtol in your case. 可用于字符串到整数转换的唯一函数是strto...组中的strtol在您的情况下为strtol

I've looked at this page a million times, and I really appreciate all the other answers for helping me out. 我已经浏览了此页面一百万次,非常感谢其他所有帮助我的答案。 Here is the stub I am using, which is unique from other answers because it can be used in a for loop: 这是我正在使用的存根,与其他答案不同,因为它可以在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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM