【问题标题】: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,所​​以有时我会出错

标签: c union type-punning c-standard-library


【解决方案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,它通常具有与双精度相同的大小,您将能够打印其整个表示。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-13
        • 2011-09-16
        • 1970-01-01
        • 1970-01-01
        • 2019-02-14
        • 1970-01-01
        • 2019-08-05
        • 1970-01-01
        相关资源
        最近更新 更多