从char *数组中读取“整数”大小的字节。

我想从char*数组中读取sizeof(int)字节。

a)在什么情况下我们需要担心是否需要检查字节序?

b)如何考虑或不考虑字节顺序,您将如何读取前4个字节。

编辑:我读过的sizeof(int)字节需要与整数值进行比较。

解决这个问题的最佳方法是什么?

你的意思是这样的吗?:

 char* a; int i; memcpy(&i, a, sizeof(i)); 

如果数据源来自不同的平台(如设备),则只需担心字节序。

a)如果数据是在big-endian机器上创建的,并且正在小端机器上处理,反之亦然,你只需要担心“字节序”(即字节交换)。 有很多方法可以实现,但这里有几个例子。

  1. 您通过套接字在Windows计算机上接收数据。 Windows采用little-endian架构,而网络数据“应该”采用big-endian格式。
  2. 您处理在具有不同“字节顺序”的系统上创建的数据文件。

在任何一种情况下,您都需要对大于1个字节的所有数字进行字节交换,例如,short,int,long,double等。但是,如果您始终处理来自同一平台的数据,则问题无关紧要。

b)根据你的问题,听起来你有一个char指针,想要将前4个字节作为int提取,然后处理任何endian问题。 要进行提取,请使用:

 int n = *(reinterpret_cast(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); 

解决这个问题的简单方法是确保以一致的字节顺序生成字节。 通常,各种TCP / IP内容使用的“网络字节顺序”是最好的:库例程htonlntohl非常适用于此,它们通常都经过相当好的优化。

但是,如果未使用网络字节顺序,则可能需要以其他方式执行操作。 您需要知道两件事:整数的大小和字节顺序。 一旦你知道了,就知道要提取多少字节以及将它们组合成int的顺序。

假设sizeof(int)的一些示例代码是正确的字节数:

 #include  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  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循环吗?

 void ReadBytes(char * stream) { for (int i = 0; i < sizeof(int); i++) { char foo = stream[i]; } } } 

你要求的东西比那更复杂吗?

只有当您正在读取的数据由大于一个字节的数字组成时,才需要担心字节顺序。
如果你正在读取sizeof(int)字节并希望将它们解释为int,则endianess会产生影响。 基本上字节顺序是机器将一系列超过1个字节解释为数值的方式。

只需使用在sizeof(int)块中移动数组的for循环。
使用函数ntohl (位于头文件 ,至少在Linux上)将网络顺序中的字节(网络顺序定义为big-endian)转换为本地字节顺序。 该库函数用于为您运行的任何处理器执行正确的网络到主机转换。

为何可以比较时阅读?

 bool AreEqual(int i, char *data) { return memcmp(&i, data, sizeof(int)) == 0; } 

当你需要将所有整数转换为某种不变forms时,如果你担心字节序。 htonl和ntohl就是很好的例子。