我想从一个 char*
数组中读取 sizeof(int)
个字节。
a) 在哪些情况下需要担心需要检查字节序?
b) 如何读取前4个字节,无论是否考虑字节序。
编辑 : 我已经读取了 sizeof(int)
字节,需要将其与一个整数值进行比较。
如何最好地解决这个问题?
我想从一个 char*
数组中读取 sizeof(int)
个字节。
a) 在哪些情况下需要担心需要检查字节序?
b) 如何读取前4个字节,无论是否考虑字节序。
编辑 : 我已经读取了 sizeof(int)
字节,需要将其与一个整数值进行比较。
如何最好地解决这个问题?
你的意思是像这样吗?
char* a;
int i;
memcpy(&i, a, sizeof(i));
只有当数据来源于不同的平台(比如设备)时,才需要担心字节顺序问题。
a) 如果数据是由大端机器创建并在小端机器上处理,或者反之,则只需关注“字节顺序”(即字节交换)问题。这种情况有很多种可能性,以下是其中的几个示例:
在任一情况下,您都需要对大于1个字节的所有数字执行字节交换,例如shorts、ints、longs、doubles等。但是,如果您始终处理来自同一平台的数据,则字节顺序问题就不是问题了。
b) 根据您的问题,似乎您有一个char指针,并希望提取前4个字节作为int,然后再处理任何字节顺序问题。要执行提取,请使用以下代码:
int n = *(reinterpret_cast<int *>(myArray)); // where myArray is your data
显然,这里假定myArray不是空指针;否则,它会崩溃,因为它对指针进行了解引用,所以要采用良好的防御性编程策略。
在Windows上交换字节,您可以使用winsock2.h中定义的ntohs()/ntohl()和/或htons()/htonl()函数。或者,您可以编写一些简单的C++程序来执行此操作,例如:
inline unsigned short swap_16bit(unsigned short us)
{
return (unsigned short)(((us & 0xFF00) >> 8) |
((us & 0x00FF) << 8));
}
inline unsigned long swap_32bit(unsigned long ul)
{
return (unsigned long)(((ul & 0xFF000000) >> 24) |
((ul & 0x00FF0000) >> 8) |
((ul & 0x0000FF00) << 8) |
((ul & 0x000000FF) << 24));
}
根据您想要如何读取它们,我感觉您想将4个字节转换为整数,如果在网络流数据上这样做,通常会得到以下结果:
int foo = *(int*)(stream+offset_in_stream);
#include <limits.h>
int bytes_to_int_big_endian(const char *bytes)
{
int i;
int result;
result = 0;
for (i = 0; i < sizeof(int); ++i)
result = (result << CHAR_BIT) + bytes[i];
return result;
}
int bytes_to_int_little_endian(const char *bytes)
{
int i;
int result;
result = 0;
for (i = 0; i < sizeof(int); ++i)
result += bytes[i] << (i * CHAR_BIT);
return result;
}
#ifdef TEST
#include <stdio.h>
int main(void)
{
const int correct = 0x01020304;
const char little[] = "\x04\x03\x02\x01";
const char big[] = "\x01\x02\x03\x04";
printf("correct: %0x\n", correct);
printf("from big-endian: %0x\n", bytes_to_int_big_endian(big));
printf("from-little-endian: %0x\n", bytes_to_int_little_endian(little));
return 0;
}
#endif
你能行吗?
int int_from_bytes(const char * bytes, _Bool reverse)
{
if(!reverse)
return *(int *)(void *)bytes;
char tmp[sizeof(int)];
for(size_t i = sizeof(tmp); i--; ++bytes)
tmp[i] = *bytes;
return *(int *)(void *)tmp;
}
您可以像这样使用它:
int i = int_from_bytes(bytes, SYSTEM_ENDIANNESS != ARRAY_ENDIANNESS);
如果您的系统中将 void *
转换为 int *
可能会导致对齐冲突,可以使用下面的方法:
int int_from_bytes(const char * bytes, _Bool reverse)
{
int tmp;
if(reverse)
{
for(size_t i = sizeof(tmp); i--; ++bytes)
((char *)&tmp)[i] = *bytes;
}
else memcpy(&tmp, bytes, sizeof(tmp));
return tmp;
}
只需使用一个for循环,以sizeof(int)块移动数组。
使用函数ntohl
(在头文件<arpa/inet.h>
中找到,至少在Linux上),将字节从网络顺序(网络顺序定义为大端)转换为本地字节顺序。该库函数被实现为执行适用于您正在运行的任何处理器的正确网络到主机转换。
你不必担心字节序,除非你正在读取来自不同机器的源数据,例如网络流。
既然如此,难道你不能只是使用for循环吗?
void ReadBytes(char * stream) {
for (int i = 0; i < sizeof(int); i++) {
char foo = stream[i];
}
}
}
你是在问比那更复杂的东西吗?
为什么要阅读,当你可以直接比较呢?
bool AreEqual(int i, char *data)
{
return memcmp(&i, data, sizeof(int)) == 0;
}
如果你需要将所有整数转换为某个不变的形式,而又担心字节序问题,那么htonl和ntohl是很好的例子。