为什么下面编写的两个程序(C 中的联合)的输出存在矛盾?
Why is there a contradiction in the output by two programs written below (Unions in C)?
这是第一个代码:
#include<stdio.h>
int main(){
union var{
int a;
int b;
};
union var v;
v.b=10;
v.a=5;
printf("%d", v.b);
return 0;
}
这给出了 5 作为输出。
但是,请考虑以下代码:
#include<stdio.h>
int main(){
union var{
int a;
float b;
};
union var v;
v.b=10.0;
v.a=5;
printf("%f", v.b);
return 0;
}
这给出了 0.000000 作为输出。
有什么解释吗?
内存中的位用于以不同的方式表示不同的类型。这个答案讨论了 int
(32 位二进制补码)和 float
(IEEE-754 binary32,也称为单精度)最常用的表示形式,假设填充位或不同顺序没有复杂性int
和 float
之间的位和字节数。
对于int
,有一个符号位和31个值位。 31 个值位被解释为二进制数字。符号位表示的值-231,int
表示的值是符号位的值与二进制数的值之和。
当你在int
成员v.a
中存储5时,5用符号位0和值位0000000000000000000000000000101表示。当你用int
成员[=19读取它时=],这些位的解释方式与它们用于表示 5 的方式相同,因此结果为 5。
当您使用 float
成员 v.b
阅读它时,这些位将使用 float
的方案重新解释。
对于float
,有一个符号位s,8个指数位e,23个有效位f,其中 e 和 f 是解释为二进制数字时的位值。这些位被解释为:
- 若e = 0,表示的值为(−1)s• 21-127•(0+f/223).
- 若0 < e < 255,表示的值为(−1)s•2e-127•(1+f/223).
- 若e = 255且f = 0,则表示的值为(−1)s•∞.
- 如果 e = 255 且 f ≠ 0,表示的值是一个特殊的非数字 (NaN) 值。 (如果设置了f的第一位,222≤f,是一个安静的NaN .否则,它是一个信令NaN。)
当位 00000000000000000000000000000101 被解释为 float
时,则 s 为 0,e 为 0,并且 f为5。这符合第一个条件,所以表示的值为(−1)0•21-127•(0+5/223) = 2−126•5•2−23 = 5•2−149,约等于7•10−45.
当你用%f
打印这个数字时,它非常小,只打印了“0.000000”。如果用 %g
打印它,输出将是“7.00649e-45”。
请注意,在 C 中,根据 C 2018 6.5.2.3 3 和注释 99,读取除最后一个写入成员之外的成员的值会将内存字节重新解释为新类型。在 C++ 中,行为是未定义。
这是第一个代码:
#include<stdio.h>
int main(){
union var{
int a;
int b;
};
union var v;
v.b=10;
v.a=5;
printf("%d", v.b);
return 0;
}
这给出了 5 作为输出。
但是,请考虑以下代码:
#include<stdio.h>
int main(){
union var{
int a;
float b;
};
union var v;
v.b=10.0;
v.a=5;
printf("%f", v.b);
return 0;
}
这给出了 0.000000 作为输出。
有什么解释吗?
内存中的位用于以不同的方式表示不同的类型。这个答案讨论了 int
(32 位二进制补码)和 float
(IEEE-754 binary32,也称为单精度)最常用的表示形式,假设填充位或不同顺序没有复杂性int
和 float
之间的位和字节数。
对于int
,有一个符号位和31个值位。 31 个值位被解释为二进制数字。符号位表示的值-231,int
表示的值是符号位的值与二进制数的值之和。
当你在int
成员v.a
中存储5时,5用符号位0和值位0000000000000000000000000000101表示。当你用int
成员[=19读取它时=],这些位的解释方式与它们用于表示 5 的方式相同,因此结果为 5。
当您使用 float
成员 v.b
阅读它时,这些位将使用 float
的方案重新解释。
对于float
,有一个符号位s,8个指数位e,23个有效位f,其中 e 和 f 是解释为二进制数字时的位值。这些位被解释为:
- 若e = 0,表示的值为(−1)s• 21-127•(0+f/223).
- 若0 < e < 255,表示的值为(−1)s•2e-127•(1+f/223).
- 若e = 255且f = 0,则表示的值为(−1)s•∞.
- 如果 e = 255 且 f ≠ 0,表示的值是一个特殊的非数字 (NaN) 值。 (如果设置了f的第一位,222≤f,是一个安静的NaN .否则,它是一个信令NaN。)
当位 00000000000000000000000000000101 被解释为 float
时,则 s 为 0,e 为 0,并且 f为5。这符合第一个条件,所以表示的值为(−1)0•21-127•(0+5/223) = 2−126•5•2−23 = 5•2−149,约等于7•10−45.
当你用%f
打印这个数字时,它非常小,只打印了“0.000000”。如果用 %g
打印它,输出将是“7.00649e-45”。
请注意,在 C 中,根据 C 2018 6.5.2.3 3 和注释 99,读取除最后一个写入成员之外的成员的值会将内存字节重新解释为新类型。在 C++ 中,行为是未定义。