我们可以对这些片段说些什么?

时间:2016-09-19 15:01:00

标签: c variables

1

a=a+b; b=a-b; a=a-b;

2

b=a+b-(a=b);

这两个片段交换'a'和'b'的值而没有临时的第三个变量。 请忽略第二个陈述的完整性质。 第二个陈述是否优于第一个陈述?怎么样? 我们可以说第二个是最优的,因为它的陈述较少吗?

3 个答案:

答案 0 :(得分:6)

这两种方法都不是通用的,因为您可能会在a+b上冒数字溢出。由于C标准考虑整数溢出undefined behavior,因此两个片段同样不好,并且在生产代码中是不可接受的。

最好的方法也是最具可读性的方法:

int tmp=a;
a=b;
b=tmp;

您的代码的读者会立即看到正在发生的事情,这本身就足够了。然而,作为额外的奖励,大多数编译器也将看到您正在做的事情,并通过在可用的平台上使用交换指令来优化代码中的tmp变量。

注意:有人可能会争辩说第二种方法更糟糕,因为a在具有副作用的表达式中使用了两次,而在两次使用之间没有序列点。这意味着允许编译器计算a=b并在计算a之前将结果存储到a+b ,即使分配之后 em>添加。即使没有整数溢出,这一操作序列的最终结果也与a=b相同。

答案 1 :(得分:2)

两种方法都是尝试交换两个变量的坏方法。如果ab属于某种无符号类型,则第一个可能在所有情况下都能正常工作(我还没有花时间确认)。如果它们都是某些签名类型,则第一个冒险整数溢出,其具有未定义的行为。如果它们都是浮点类型(问题中没有任何内容表明它们不是),则第一个存在溢出和精度损失的风险,并且不能正确处理无穷大和NaN。如果它们属于复杂类型 - 那么,让我们假设它们不是,并且它们都属于同一类型。

第二种类型具有任何类型的未定义行为,因为它在没有插入序列点的情况下读取和修改a的值。在C11标准使用的术语中,a的读写是未序列的;既不依赖于另一个,所以它们可以以任何顺序发生。 (结果不限于可能的顺序;行为明确地完全未定义。)

您(我认为)询问了两个代码段的运行时效率。错误代码的效率并不重要。

交换两个对象的方法是使用临时的:

const SOME_TYPE old_a = a;
a = b;
b = old_a;

其中SOME_TYPEab的类型。像问题中那样的愚蠢技巧,或者xor技巧,都是浪费时间。

答案 2 :(得分:0)

  

第二个陈述是否优于第一个陈述?

没有

  

如何?

不是。

  

我们可以说第二个是最优的,因为它的陈述较少吗?

没有。在生成程序集时,C编译器具有很大的自由度。这些语句中的任何一个都可以简化为更简单的组装,甚至可以完全删除,具体取决于代码的其余部分。

你不能在这两个陈述之间做出任何相对效率的陈述。