我想知道之间是否有区别:
- 将原始变量转换为另一种原始类型
- 将原始变量地址的转换取消引用到另一个原始类型的指针
我还想知道是否有充分的理由使用 (2) 而不是 (1)。我在遗留代码中看到了 (2),这就是我想知道的原因。从上下文来看,我无法理解为什么 (2) 比 (1) 更受青睐。从我编写的以下测试中,我得出结论,至少在任何一种情况下,向上转换的行为都是相同的:
/* compile with gcc -lm */
#include <stdio.h>
#include <math.h>
int main(void)
{
unsigned max_unsigned = pow(2, 8 * sizeof(unsigned)) - 1;
printf("VALUES:\n");
printf("%u\n", max_unsigned + 1);
printf("%lu\n", (unsigned long)max_unsigned + 1); /* case 1 */
printf("%lu\n", *((unsigned long *)&max_unsigned) + 1); /* case 2 */
printf("SIZES:\n");
printf("%d\n", sizeof(max_unsigned));
printf("%d\n", sizeof((unsigned long)max_unsigned)); /* case 1 */
printf("%d\n", sizeof(*((unsigned long *)&max_unsigned))); /* case 2 */
return 0;
}
输出:
VALUES:
0
4294967296
4294967296
SIZES:
4
8
8
从我的角度来看,(1) 和 (2) 之间应该没有区别,但我想咨询 SO 专家进行健全性检查。
最佳答案
第一个转换是合法的;第二次转换可能不合法。
第一个强制转换告诉编译器使用变量类型的知识来转换为所需的类型;只要语言标准中定义了正确的转换,编译器就会执行。
第二个转换告诉编译器忘记它对变量类型的了解,并将其内部表示重新解释为不同类型 *。这具有有限的适用性:只要二进制表示与目标指针指向的类型相匹配,这种转换就会起作用。然而,这并不等同于第一次转换,因为在这种情况下,值转换永远不会发生。
将要转换的变量的类型切换为具有不同表示形式的东西,例如 float
,很好地说明了这一点:第一次转换产生正确的结果,而第二次转换产生垃圾:
float test = 123456.0f;
printf("VALUES:\n");
printf("%f\n", test + 1);
printf("%lu\n", (unsigned long)test + 1);
printf("%lu\n", *((unsigned long *)&test) + 1); // Undefined behavior
这打印
123457.000000
123457
1206984705
* 只有当其中一种类型是字符类型并且指针对齐有效、类型转换很简单(即没有转换时)、更改限定符或符号时,或者当您向/从
struct
/union
转换,其中第一个成员是有效的转换源/目标。否则,这会导致未定义的行为。有关完整说明,请参阅 C 2011 (N1570),6.5 7。感谢 Eric Postpischil 指出定义第二次转换时的情况。
关于c - "(type)variable"和 "*((type *)&variable)"之间有什么区别(如果有)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20055136/