C ++:使用无位指针将Unsigned Char转换为unsigned int

时间:2018-09-28 19:05:28

标签: c++

假设我有一个unsigned char类型的C样式数组:

unsigned char * c = (unsigned char *) malloc(5000 * sizeof(unsigned char));
for(int i = 0; i < 5000; i++) 
    c[i] = (unsigned char) ((i >> (i%4 * 8)) & 0xFF);

假设我的指针偏移到以4字节整数开头的位置:

// pseudo code
unsigned int i = c + 10; // 10 = pointer offset, let's say. 

如果我想用正确的号码加载i,我可以这样做:

unsigned int i = (*(c+10) << 24) + (*(c+11) << 16) + (*(c+12) << 8) + (*(c+13));

但是我不应该以某种方式使用演员表吗?

// pseudo code -- I haven't gotten this to work yet: 

int i = (unsigned int) (*((void *)(c+10));

// or maybe
int i = *((unsigned int*)((void *)(c+10)));

简而言之,将四个字节转换为C样式字节数组中的unsigned int的最干净,最有效的方法是什么?

3 个答案:

答案 0 :(得分:6)

执行此操作的正确方法是使用memcpy:

unsigned int i;
std::memcpy(&i, c + offset, sizeof(unsigned int));

在支持不对齐变量访问的体系结构(如x86-64)上,这将被优化为简单的指针取消引用,但是在不支持不对齐访问的系统(例如ARM)上,它将做适当的事情获得价值。

例如参见:https://gcc.godbolt.org/z/l5Px4G。在用于x86的gcc和arm之间切换编译器,并查看指令中的区别。

如果要从某个外部源获取数据,请记住字节顺序的想法。您可能需要翻转整数的字节才能使值有意义。

答案 1 :(得分:3)

不,你不应该。向分配的对象的指针添加不是对象大小的倍数的偏移量可能会导致平台无法取消引用。它只是不是指向unsigned int的指针。

在某些平台上,性能会很糟糕。在某些平台上,代码将出错。

无论如何,转换和添加都非常清楚并且易于理解。转换更加混乱,需要了解平台的字节顺序。因此,您并没有使事情变得更好,更简单或更清晰。

答案 2 :(得分:3)

  

但是我不应该以某种方式使用演员表吗?

不,没有可以保证工作的演员表。


请注意,整数有很多表示形式。如何将字节数组转换为整数对象取决于整数在数组中的表示方式。例如,如果将整数转换为字节数组并通过网络发送,您将无法知道接收计算机是否使用相同的表示形式。

一个考虑因素是负数如何表示。幸运的是2的补码是如此普遍,我们通常可以忽略它。不过,就您而言,它要转换的更重要,因为您要转换无符号整数。

更相关的考虑因素是字节字节序。

如果您知道该数组与执行程序的CPU具有相同的表示形式,则可以使用std::memcpy复制字节:

unsigned int i;
static_assert(sizeof i == 4);
std::memcpy(&i, c + 10, sizeof i);

只要源数据使用相同的表示形式,无论CPU使用哪种字节顺序,此方法都能正常工作。


您的建议(*(c+10) << 24) + ...是正确的(或者似乎是,我没有彻底检查过)字节数组的表示形式是否为大端。如果数组很小或其他字节序,则建议是错误的。

此方法在通过网络接收数据时非常有用,因为它不依赖于表示与执行CPU相同的表​​示形式。