为什么转换为指针然后取消引用?

2021-12-31 00:00:00 c casting c++

我正在研究这个例子,它有一个输出十六进制位模式来表示任意浮点数的函数.

I was going through this example which has a function outputting a hex bit pattern to represent an arbitrary float.

void ExamineFloat(float fValue)
{
    printf("%08lx
", *(unsigned long *)&fValue);
}

为什么取 fValue 的地址,转换为无符号长指针,然后解引用?所有这些工作不都等同于直接转换为 unsigned long 吗?

Why take the address of fValue, cast to unsigned long pointer, then dereference? Isn't all that work just equivalent to a direct cast to unsigned long?

printf("%08lx
", (unsigned long)fValue);

我试过了,答案不一样,很困惑.

I tried it and the answer isn't the same, so confused.

推荐答案

(unsigned long)fValue

根据通常的算术转换",这会将 float 值转换为 unsigned long 值.

This converts the float value to an unsigned long value, according to the "usual arithmetic conversions".

*(unsigned long *)&fValue

这里的目的是取fValue存储的地址,假设没有float而是unsigned long这个地址,然后读取那个unsigned long.目的是检查用于在内存中存储 float 的位模式.

The intention here is to take the address at which fValue is stored, pretend that there is not a float but an unsigned long at this address, and to then read that unsigned long. The purpose is to examine the bit pattern which is used to store the float in memory.

如图所示,这会导致未定义的行为.

原因:您不能通过指向与对象类型不兼容"的类型的指针来访问对象.例如,兼容"类型是 (unsigned) char 和所有其他类型,或者共享相同初始成员的结构(这里说的是 C).详见 §6.5/7 N1570(C11) 列表(请注意,我对兼容"的使用与引用文本中的不同 - 更广泛.)

Reason: You may not access an object through a pointer to a type that is not "compatible" to the object's type. "Compatible" types are for example (unsigned) char and every other type, or structures that share the same initial members (speaking of C here). See §6.5/7 N1570 for the detailed (C11) list (Note that my use of "compatible" is different - more broad - than in the referenced text.)

解决方案:转换为unsigned char *,访问对象的各个字节并从中组合一个unsigned long:

Solution: Cast to unsigned char *, access the individual bytes of the object and assemble an unsigned long out of them:

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 指出的那样)以上将浮点值视为首先存储其最高有效字节(大端").如果您的系统对浮点值使用不同的字节顺序,您需要对此进行调整(或重新排列上述 unsigned long 的字节,无论对您来说更实用).

Note that (as @CodesInChaos pointed out) the above treats the floating point value as being stored with its most significant byte first ("big endian"). If your system uses a different byte order for floating point values you'd need to adjust to that (or rearrange the bytes of above unsigned long, whatever's more practical to you).

相关文章