奇怪的C++类型转换

3

在跟随 OpenGL 教程 时,我遇到了这段代码:

unsigned char header[54];

// [...]

unsigned int dataPos = *(int*)&(header[0x0A]);

我不理解使用*(int*)&的用法。为什么不直接使用(int)


8
如果我没错的话,*(int*)&(header[0x0A]) 看起来像是一个严格别名违规。 - mediocrevegetable1
3个回答

3

header 是一个 char 数组,这里的转换是将 header 在位置 0x0A地址转换成一个 int* 指针,然后从那个地址读取数据,就好像它是一个 int。实际上,它将从位置 0x0A 开始读取头部的4个字节(或者一个int在你的系统上的大小),并将它们打包成一个单独的整数。

简单的 (int) 转换只会将在位置 0x0A 上的值从 char 转换为 int,但不会获得其余3个字节上的值。


2
为什么不直接使用(int)?因为(int)header[0x0A]只会将地址0x0A处的一个字节转换,而本意是重新解释一系列sizeof(int)个字节。话虽如此,该示例行为未定义,因为它违反了“严格别名规则”。此外,我不知道他们为什么要强制转换为int*再转换为unsigned int。一个明确定义的替代方案:
std::memcpy(&dataPos, header + 0xA, sizeof dataPos);

在这种情况下,有没有一种简洁的方法来遵守“严格别名”? - Garfield1002
2
@Garfield1002 我认为 std::memcpy(&dataPos, &header[0xA], sizeof dataPos) 应该可以解决问题。 - mediocrevegetable1
1
我想提醒大家,这种指针算术并不安全。在这种情况下它可以工作,但如果某种花哨的新编译器将char定义为2个或更多字节,则会悄悄地创建运行时问题。std::memcpy(&dataPos, &header[0xA], sizeof dataPos); 更安全且符合MISRA标准。 - Murat Ursavaş
@MuratUrsavaş &header[0xA]header + 0xA 是完全等价的,就我所知,它们之间没有更安全的一种。char 的定义总是恰好1个字节,永远不会超过。如果您的意思是当一个字节的大小不同于8位时可能会出现问题,那么&header[0xA]也会有同样的问题。如果MISRA要求使用前一种风格,并且您需要符合MISRA,则请务必使用该风格,但这只是一种风格问题。 - eerorika
@eerorika 我知道,char的定义恰好是一个字节,而且新编译器具有不同的char大小的可能性非常低。将此视为所有类型的经验法则建议。指针算术通常会导致错误,这些错误可以很容易地避免。我们都会这样做,最好远离它。MISRA规则是由于这个原因而创建的,而不仅仅是某种编码风格。 - Murat Ursavaş

0

*(int*)&(header[0x0A]); 的意思是首先将 &header[0x0A] 强制转换为 int* 以匹配 header 的类型,然后使用 * 解引用整个变量,使得结果不再是指针。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接