使用 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.0double 有很多 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