我正在查看我继承的一些旧代码,我真的不喜欢某些地方的样式。我真的不喜欢它的外观之一是:
bool func() {
bool ret = true;
ret &= test1();
homemade_assert_like_function(ret == true);
ret &= test2();
homemade_assert_like_function(ret == true);
return ret;
}
我认为以下内容更清晰:
bool func() {
homemade_assert_like_function(test1());
homemade_assert_like_function(test2());
return true; // just to keep the interface
}
但是,后者会产生更多的汇编代码。毫不奇怪,如果我将第一个示例中的&=
更改为=
,则结果与assert(test());
相同,但是&=
似乎仍然更好
对于所有三个示例,我都将gcc5.4用于带-O2的mips,但是如果对pc使用gcc,则结果是相似的。如果我使用-std = c ++ 14(和更新的编译器)进行编译,则这三个示例将生成相同的代码。
有人可以向我解释吗?仅仅是我的测试代码真的很糟糕吗?
编辑:
我制作了一个新的代码示例,修复了损坏的断言。它确实有一个有趣的副作用。现在,大小差异要小得多,这向我表明,优化器必须能够在&=
情况下发挥某些作用。
正如已经多次指出的那样,示例代码有些模糊。但它显示出的效果与我在真实代码中看到的效果相同-除了删除&=
代码风格之外,什么都不做,只会增加代码库。
答案 0 :(得分:3)
此代码正在尝试以使用快捷方式评估,但失败。
(代码错误)
首先,让我展示一下 meant 要做的事情:
代码应为:
bool func() {
bool ret = true;
ret = ret && test1();
homemade_assert_like_function(ret == true);
ret = ret && test2();
homemade_assert_like_function(ret == true);
return ret;
}
重要的是,如果ret
已经是false
,表明结果失败了,它甚至不会尝试计算表达式的第二部分! (test1()
或test2()
)。
如果函数test()
有任何副作用,则一旦ret
标志指示失败后,它将不会运行。
这对于经历漫长的多步骤过程(test1()
... testN()
)很有用,并且一旦单个步骤失败就不再执行任何工作。
现在,这段代码实际上在做什么,为什么?
ret
从true
开始,一旦其中一个功能失败,ret就会变为false,并停留在false(只要操作始终为&=
。 / p>
但是,与我之前写的不同,即使先前的测试已经失败,每个函数test1()
,test2()
,testN()
仍然可以运行(包括副作用)!
这与他们将代码编写为:
bool func() {
bool ret = true;
ret = test1();
homemade_assert_like_function(ret == true);
ret = test2();
homemade_assert_like_function(ret == true);
return ret;
}
与您建议的代码的最大区别是您的代码 始终 返回true
。您如何假设每个测试都成功?测试失败时,应允许代码返回false
。您从代码版本中删除了该功能。
答案 1 :(得分:-1)
我认为这是不必要的复杂测试代码。如果仅反汇编该函数本身,就会发现对该函数的外观更改导致接近相同的代码。实际上,它们会导致代码更快。
我摆脱了所有毫无意义的混淆,写了一个可读的版本:
#include <stdbool.h>
bool func (void) {
assert(test1());
assert(test2());
return true;
}
关于gcc x86-64 9.2 -O2的11条说明。但是您的原始版本提供了15条说明。将函数类型更改为bool
会导致代码稍有不同,但是干净版本仍然更有效。
然而,这里的重要部分是编写可读性最高的代码。像bool ret = true; ret &= test1();
这样的怪异事物简直是毫无意义的。