【问题标题】:Why a and b are not swapped in this code?为什么在这段代码中 a 和 b 没有交换?
【发布时间】:2016-02-28 23:33:40
【问题描述】:

代码如下:

#include <stdio.h>

union
{
    unsigned u;
    double d;
} a,b;

int main(void)
{
    printf("Enter a, b:");
    scanf("%lf %lf",&a.d,&b.d);
    if(a.d>b.d)
    {
        a.u^=b.u^=a.u^=b.u;
    }
    printf("a=%g, b=%g\n",a.d,b.d);
    return 0;
}

a.u^=b.u^=a.u^=b.u; 语句应该交换了 ab if a&gt;b,但似乎无论我输入什么,输出始终是我的输入。

【问题讨论】:

  • 我只想说,如果可读性和可维护性对您有任何价值,您应该找到一种更简单的方法来完成这项任务。不是我知道的答案,但是...
  • 想想工会是如何运作的,并考虑 sizeof(a.u) 与 sizeof(a.d)。
  • 我认为(但我不确定)写入a.d 然后从a.u 读取是未定义的行为。你有优化吗?
  • @keithmo 我明白了,谢谢!
  • @immibis 我不确定。作为一个新手程序员,我只需打开 code::blocks,输入我的代码,然后按 F9。关于编译器我什么都没碰。

标签: c unions bit-fields


【解决方案1】:

在通常的环境中,数据类型'unsigned'和'double'的内存大小是不同的。 这就是变量看起来没有变化的原因。

而且你不能对浮点变量使用异或交换。 因为它们在内存中的表现完全不同。

【讨论】:

  • 如果大小相同,您可以。问题是他们可能不是。
【解决方案2】:

double 很可能是 64 位,而 unsigned 只有 32 位。当你交换工会的unsigned 成员时,你只得到了doubles 的一半。

如果您将d 更改为float,或将u 更改为unsigned long long,它可能会起作用,因为它们的大小可能相同。

您还通过在没有序列点的情况下两次写入变量来导致 UB。编写 XOR 交换的正确方法是使用多个语句。

b.u ^= a.u;
a.u ^= b.u;
b.u ^= a.u;

有关为什么不使用 XOR 进行交换的更多信息,请参阅Why don't people use xor swaps?

【讨论】:

  • @M.M 未指定或依赖于实现,那么?
  • @M.M 但是由于尺寸和对齐方式不存在问题吗?如果你读的成员比你写的多,你正在访问未初始化的内存。
  • 好的,我已经删除了有关该问题的任何内容。
【解决方案3】:

a.u^=b.u^=a.u^=b.u; 在没有序列点的情况下两次写入a.u 会导致未定义的行为。 See here 讨论此代码。

你可以写:

unsigned tmp;
tmp = a.u;
a.u = b.u;
b.u = tmp;

这将交换a.ub.u。但是,如果 double 在您的系统上是比 unsigned 更大的类型(常见情况),这可能无法实现交换两个双精度的目标。

【讨论】:

  • 他使用联合的全部意义在于他可以使用异或交换而不是临时变量。
  • @Barmar 那么他运气不好
猜你喜欢
  • 2022-09-22
  • 2013-06-25
  • 1970-01-01
  • 1970-01-01
  • 2021-09-10
  • 2017-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多