使用 Type Punning 和 union 的问题
Issue using Type Punning with union
我想了解有关类型双关和别名的更多信息。所以我使用 GCC documentation 选项 -fstric-aliasing
提供的代码,如下所示:
union a_union{
int i;
double d;
};
int f(){
union a_union t;
t.d=3.0;
return t.i
}
/*what I add*/
int main(int argc, char *argv[])
{
printf("%d\n",f());
return 0;
}
我没有期待什么特别的,但我只得到 0。所以我用 t.d
的不同值进行测试,但没有变化。
我在没有选项的情况下使用 gcc 6.3 在 Debian 9 上测试了这段代码。
我也尝试使用选项 -fno-strict-aliasing
相同的结果
如果有人能解释一下,为什么我只得到 0 那就太好了
一个值为 3.0
的 double
有很多 0 字节。我假设你的机器的字节顺序是这样的,它们与 int 重叠。如果您使用的不是 3.0
,而是 3.1
,您应该会看到另一个值。
您也可以尝试使用 unsigned long long
而不是 int
,它通常与双精度数具有相同的大小,您将能够打印它的整个表示。
这取决于您的特定处理器使用的存储类型。
3.0000000000000000(双精度3)表示为4008 0000 0000 0000(十六进制)
您的处理器可以按各种顺序存储浮点数,有些会先存储最不重要的 bytes/words。在那种情况下,int 只会 return 0000 0000.
尝试使用 Pi 或 sqrt(2)
成员的大小在任何常见系统中都不匹配。 int
现在通常是 32 位,而 double
是 64 位。由于小端存储,3.0000000000
末尾的零位对应于 int
成员的零位。
试试这个:
#include <inttypes.h>
#include <stdio.h>
union q_union{
uint64_t i;
double d;
};
_Static_assert(sizeof (union q_union){}.i == sizeof (union q_union){}.d,
"The sizes of double and uint64_t must match");
uint64_t f(void) {
union q_union t;
t.d = 3.0;
return t.i;
}
int main(int argc, char *argv[])
{
printf("%" PRIu64 "\n", f());
printf("%#" PRIx64 "\n", f());
return 0;
}
输出:
4613937818241073152
0x4008000000000000
我想了解有关类型双关和别名的更多信息。所以我使用 GCC documentation 选项 -fstric-aliasing
提供的代码,如下所示:
union a_union{
int i;
double d;
};
int f(){
union a_union t;
t.d=3.0;
return t.i
}
/*what I add*/
int main(int argc, char *argv[])
{
printf("%d\n",f());
return 0;
}
我没有期待什么特别的,但我只得到 0。所以我用 t.d
的不同值进行测试,但没有变化。
我在没有选项的情况下使用 gcc 6.3 在 Debian 9 上测试了这段代码。
我也尝试使用选项 -fno-strict-aliasing
相同的结果
如果有人能解释一下,为什么我只得到 0 那就太好了
一个值为 3.0
的 double
有很多 0 字节。我假设你的机器的字节顺序是这样的,它们与 int 重叠。如果您使用的不是 3.0
,而是 3.1
,您应该会看到另一个值。
您也可以尝试使用 unsigned long long
而不是 int
,它通常与双精度数具有相同的大小,您将能够打印它的整个表示。
这取决于您的特定处理器使用的存储类型。
3.0000000000000000(双精度3)表示为4008 0000 0000 0000(十六进制)
您的处理器可以按各种顺序存储浮点数,有些会先存储最不重要的 bytes/words。在那种情况下,int 只会 return 0000 0000.
尝试使用 Pi 或 sqrt(2)
成员的大小在任何常见系统中都不匹配。 int
现在通常是 32 位,而 double
是 64 位。由于小端存储,3.0000000000
末尾的零位对应于 int
成员的零位。
试试这个:
#include <inttypes.h>
#include <stdio.h>
union q_union{
uint64_t i;
double d;
};
_Static_assert(sizeof (union q_union){}.i == sizeof (union q_union){}.d,
"The sizes of double and uint64_t must match");
uint64_t f(void) {
union q_union t;
t.d = 3.0;
return t.i;
}
int main(int argc, char *argv[])
{
printf("%" PRIu64 "\n", f());
printf("%#" PRIx64 "\n", f());
return 0;
}
输出:
4613937818241073152
0x4008000000000000