1
a=a+b; b=a-b; a=a-b;
2
b=a+b-(a=b);
这两个片段交换'a'和'b'的值而没有临时的第三个变量。 请忽略第二个陈述的完整性质。 第二个陈述是否优于第一个陈述?怎么样? 我们可以说第二个是最优的,因为它的陈述较少吗?
答案 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)
两种方法都是尝试交换两个变量的坏方法。如果a
和b
属于某种无符号类型,则第一个可能在所有情况下都能正常工作(我还没有花时间确认)。如果它们都是某些签名类型,则第一个冒险整数溢出,其具有未定义的行为。如果它们都是浮点类型(问题中没有任何内容表明它们不是),则第一个存在溢出和精度损失的风险,并且不能正确处理无穷大和NaN。如果它们属于复杂类型 - 那么,让我们假设它们不是,并且它们都属于同一类型。
第二种类型具有任何类型的未定义行为,因为它在没有插入序列点的情况下读取和修改a
的值。在C11标准使用的术语中,a
的读写是未序列的;既不依赖于另一个,所以它们可以以任何顺序发生。 (结果不限于可能的顺序;行为明确地完全未定义。)
您(我认为)询问了两个代码段的运行时效率。错误代码的效率并不重要。
交换两个对象的方法是使用临时的:
const SOME_TYPE old_a = a;
a = b;
b = old_a;
其中SOME_TYPE
是a
和b
的类型。像问题中那样的愚蠢技巧,或者xor技巧,都是浪费时间。
答案 2 :(得分:0)
第二个陈述是否优于第一个陈述?
没有
如何?
不是。
我们可以说第二个是最优的,因为它的陈述较少吗?
没有。在生成程序集时,C编译器具有很大的自由度。这些语句中的任何一个都可以简化为更简单的组装,甚至可以完全删除,具体取决于代码的其余部分。
你不能在这两个陈述之间做出任何相对效率的陈述。