我正在浏览这个示例,该示例具有输出十六进制位模式以表示任意 float 的函数。
void ExamineFloat(float fValue)
{
printf("%08lx\n", *(unsigned long *)&fValue);
}
为什么取fValue的地址,转换成无符号长指针,然后解引用?所有这些工作不都等同于直接转换为 unsigned long 吗?
printf("%08lx\n", (unsigned long)fValue);
我试过了,答案不一样,很困惑。
最佳答案
(unsigned long)fValue
根据“通常的算术转换”,这会将 float
值转换为 unsigned long
值。
*(unsigned long *)&fValue
这里的意图是取fValue
存储的地址,假装没有float
而是unsigned long
这个地址,然后读取那个 unsigned long
。目的是检查用于在内存中存储 float
的位模式。
如图所示,这会导致未定义的行为。
原因:您不能通过指向与对象类型不“兼容”的类型的指针来访问对象。 “兼容”类型例如是 (unsigned
) char
和所有其他类型,或共享相同初始成员的结构(这里说的是 C)。见§6.5/7 N1570对于详细的 (C11) 列表(请注意,我对“兼容”的使用与引用文本中的不同 - 更广泛。)
解决方案:转换为 unsigned char *
,访问对象的各个字节并从中组装出 unsigned long
:
unsigned long pattern = 0;
unsigned char * access = (unsigned char *)&fValue;
for (size_t i = 0; i < sizeof(float); ++i) {
pattern |= *access;
pattern <<= CHAR_BIT;
++access;
}
请注意(正如@CodesInChaos 指出的那样)上面将浮点值视为首先存储其最高有效字节(“big endian”)。如果您的系统对浮点值使用不同的字节顺序,您需要进行调整(或重新排列上述 unsigned long
的字节,对您来说更实用)。
关于c++ - 为什么要转换为指针然后取消引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39312058/