使用带有联合的类型双关语的问题

Posted

技术标签:

【中文标题】使用带有联合的类型双关语的问题【英文标题】:Issue using Type Punning with union 【发布时间】:2019-11-20 17:07:48 【问题描述】:

我想了解有关类型双关语和别名的更多信息。所以我使用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 的不同值,但没有变化。 我在 Debian 9 上使用 gcc 6.3 测试此代码,没有选项。 我也尝试使用选项-fno-strict-aliasing 相同的结果

如果有人可以解释一下,为什么我只得到 0 那就太好了

【问题讨论】:

您的代码中有a_unionq_union。这实际上是您的代码,还是您在复制粘贴时出错了? 哦,那是因为我用了两台电脑,一台是azerty键盘,另一台是qwerty,所​​以有时我会出错 【参考方案1】:

这取决于您的特定处理器使用的存储类型。

3.0000000000000000(双精度3)用4008 0000 0000 0000(十六进制)表示

您的处理器可以按各种顺序存储浮点数,其中一些首先存储最低有效字节/字。在这种情况下,int 只会返回 0000 0000。

尝试使用 Pi 或 sqrt(2)

【讨论】:

【参考方案2】:

成员的大小在任何常见系统中都不匹配。 int 现在通常是 32 位,double 是 64 位。由于采用 little-endian 存储,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

【讨论】:

【参考方案3】:

具有3.0 值的double 有很多0 字节。我假设你的机器的字节序是这样的,它们与 int 重叠。如果您使用的是3.1 而不是3.0,您应该会看到另一个值。

除了int,您也可以尝试使用unsigned long long,它通常具有与双精度相同的大小,您将能够打印其整个表示。

【讨论】:

以上是关于使用带有联合的类型双关语的问题的主要内容,如果未能解决你的问题,请参考以下文章

是否通过 C99 中未指定的联合进行类型双关,并且它是否已在 C11 中指定?

什么是类型双关语,它的目的是什么?

memcpy 可以用于类型双关语吗?

带有 react-dnd 的 TypeScript 2.0 给出错误“JSX 元素属性可能不是联合类型”

C++ 构建警告:取消引用类型双关指针将破坏严格别名规则

强制转换和强制转换有啥区别?