我的问题是关于我在主题中提到的行,我可以在生产代码中的许多地方看到它。
整体代码如下所示:
if (0) {
// Empty braces
} else if (some_fn_call()) {
// actual code
} else if (some_other_fn_call()) {
// another actual code
...
} else {
// default case
}
其他分支与我的问题无关。我想知道将 if (0)
放在这里是什么意思。大括号是空的,所以我不认为它应该注释一些代码块。它会强制编译器进行一些优化还是它的意图不同?
我试图在 SO 和互联网上搜索这个明确的案例,但没有成功。关于 JavaScript 有类似的问题,但 C 没有。还有另一个问题 What happens when a zero is assigned in an `if` condition?,但它讨论了对变量的零赋值,而不是“if (0)”用法本身。
如果有 #if
语句,这可能很有用,ala
if (0)
{
// Empty block
}
#if TEST1_ENABLED
else if (test1())
{
action1();
}
#endif
#if TEST2_ENABLED
else if (test2())
{
action2();
}
#endif
等等
在这种情况下,任何(和所有)测试都可以#if
退出,并且代码将正确编译。几乎所有编译器都会删除 if (0) {}
部分。一个简单的自动生成器可以生成这样的代码,因为它更容易编码 - 它不必单独考虑第一个启用的块。
我有时将它用于对称,因此我可以用我的编辑器自由移动另一个 else if{
,而不必介意第一个 if
。
语义上
if (0) {
// Empty braces
} else
部分不做任何事情,您可以指望优化器将其删除。
if else
前缀很好地排列了条件并使扫描它们更容易。 (不过,这是主观的,并且取决于条件和代码块中的很多内容。)
if (0) {..}
不会引入任何可解析性/可读性问题。任何懂一点 C 的人都应该明白这一点。这不是问题。问题是阅读后的后续问题:“那到底是为了什么?”除非是出于调试/临时目的(即,目的是稍后“启用”该 if
块),否则我会提倡完全删除。基本上“阅读”这样的代码可能会无缘无故地给读者造成不必要的“暂停”。这是一个足够好的理由来删除它。
else if
”,因为条件可能不是互斥的,在这种情况下 order 很重要。我个人只会使用 if
,并执行 early return,如有必要,将逻辑链提取到单独的函数中。
我在生成的代码中看到了类似的模式。例如,在 SQL 中,我看到库发出以下 where
子句。
where 1 = 1
这大概使添加其他条件变得更容易,因为所有其他条件都可以在前面加上 and
,而不是额外检查它是否是第一个条件。
1=1
也是“有用的”,因为您始终可以无条件地将 where
添加到前面。否则,您必须检查它是否为空,如果是,请避免生成 where
子句。
WHERE
中“删除”1=1
,因此不会影响性能。
如所写,if (0) {}
子句编译为空。
我怀疑这个阶梯顶部的子句的功能是提供一个简单的地方,通过将 0
更改为 1
或 true
来一次性暂时禁用所有其他功能(用于调试或比较目的) .
一种尚未提及的可能性:if (0) {
行可能为断点提供了一个方便的位置。
调试通常是在未优化的代码上进行的,因此总是错误的测试将存在并且能够在其上设置断点。当为生产编译时,代码行将被优化。看似无用的行为开发和测试构建提供了功能,而不会影响发布构建。
上面还有其他很好的建议;真正知道目的是什么的唯一方法是追踪作者并询问。您的源代码控制系统可能会对此有所帮助。 (寻找 blame
类型的功能。)
我不确定是否有任何优化,但我的两分钱:
发生这种情况是因为一些代码修改,其中一个主要条件被删除(假设在初始 if
块中的函数调用),但是开发人员/维护人员
懒得重组 if-else 块
不想降低分支覆盖率
因此,他们没有删除关联的 if
块,而是简单地将条件更改为 if(0)
并继续前进。
if(0)
是不是也减少了分支覆盖率?
这是代码腐烂。
在某些时候,“如果”做了一些有用的事情,情况发生了变化,也许被评估的变量被删除了。
修复/更改系统的人尽可能少地影响系统的逻辑,所以他只是确保代码会重新编译。所以他留下了一个“if(0)”,因为这既快速又简单,而且他不完全确定这是他想要做的。他让系统正常工作,他不会回去完全修复它。
然后下一个开发人员出现并认为这是故意完成的并且只注释掉那部分代码(因为它无论如何都没有被评估),然后在下次触及代码时这些注释被删除。
我在使用模板语言生成的预扩展 JavaScript 中看到了不可访问的代码块。
例如,您正在阅读的代码可能是从服务器粘贴的,该服务器预先评估了当时依赖于仅在服务器端可用的变量的第一个条件。
if ( ${requestIsNotHttps} ){ ... }else if( ...
一旦预编译,因此:
if ( 0 ){ ... }else if ( ...
希望这可以帮助您了解我表现出热情的亲回收编码器时代潜在的低键盘活动!
该构造也可以在 C 中用于实现具有类型安全性的泛型编程,这取决于编译器仍会检查无法访问的代码这一事实:
// this is a generic unsafe function, that will call fun(arg) at a later time
void defer(void *fun, void *arg);
// this is a macro that makes it safer, by checking the argument
// matches the function signature
#define DEFER(f, arg) \
if(0) f(arg); \ // never actually called, but compile-time checked
else defer(f, (void *)arg); // do the unsafe call after safety check
void myfunction(int *p);
DEFER(myfunction, 42); // compile error
int *b;
DEFER(myfunction, b); // compiles OK
我认为这只是糟糕的代码。在 Compiler Explorer 中编写一个快速示例,我们看到在 gcc 和 clang 中都没有为 if (0)
块生成代码,即使完全禁用了优化:
尝试删除 if (0)
不会对生成的代码进行任何更改,因此我得出结论,这不是优化。
顶部 if
块中可能曾经有一些东西后来被删除了。简而言之,删除它似乎会导致生成完全相同的代码,所以请随意这样做。
如前所述,零被评估为假,编译器可能会优化分支。
我之前在代码中也看到过这一点,其中添加了一个新功能并且需要一个终止开关(如果该功能出现问题,您可以将其关闭),一段时间后,当终止开关被删除时程序员也没有删除分支,例如
if (feature_a_active()) {
use_feature_a();
} else if (some_fn()) {
...
变成了
if (0) {
// empty
} else if (some_fn()) {
...
@PSkocik 的回答很好,但我加了两分钱。不确定我应该将其作为评论还是作为答案;选择后者,因为恕我直言,值得其他人看到,而评论通常是不可见的。
我不仅偶尔使用
if(0) {
//deliberately left empty
} else if( cond1 ) {
//deliberately left empty
} else if( cond2 ) {
//deliberately left empty
...
} else {
// no conditions matched
}
但我也偶尔会
if( 1
&& cond1
&& cond2
...
&& condN
) {
或者
if( 0
|| cond1
|| cond2
...
|| condN
) {
对于复杂的条件。出于同样的原因 - 更易于编辑、#ifdef 等。
就此而言,在 Perl 我会做
@array = (
elem1,
elem2,
...
elem1,
) {
注意列表末尾的逗号。我忘记了逗号是 C 和 C++ 列表中的分隔符还是定界符。恕我直言,这是我们学到的一件事:[Perl 中的尾随逗号是一种不好的做法吗?逗号] 是个好东西。像任何新符号一样,需要一段时间才能习惯。
我将 if(0)
代码与 lisp 进行比较
(cond (test1 action1)
(test2 action2)
...
(testn actionn))
你猜对了,我可以缩进为
(cond
(test1 action1)
(test2 action2)
...
(testn actionn)
)
我有时会尝试想象一种更易于人类阅读的语法可能是什么样子。
也许
IF
:: cond1 THEN code1
:: cond2 THEN code2
...
:: condN THEN codeN
FI
受到 Dikstra 的 [https://en.wikipedia.org/wiki/Guarded_Command_Language#Selection:_if][Guarded 命令语言] 的启发。
但是这种语法意味着条件是并行评估的,而 if...else-if
意味着条件的顺序和优先级评估。
我在编写生成其他程序的程序时开始做这种事情,这特别方便。
当我们这样做时,在使用英特尔的旧 iHDL 编写 RTL 时,我编写了类似的代码
IF 0 THEN /*nothing*/
**FORC i FROM 1 TO 10 DOC**
ELSE IF signal%i% THEN
// stuff to do if signal%i% is active
**ENDC**
ELSE
// nothing matched
ENDIF
其中 FORC..DOC..ENDC
是一个宏预处理器循环构造,它扩展为
IF 0 THEN /*nothing*/
ELSE IF signal1 THEN
// stuff to do if signal1 is active
ELSE IF signal2 THEN
// stuff to do if signal2 is active
...
ELSE IF signal100 THEN
// stuff to do if signal100 is active
ELSE
// nothing matched
ENDIF
这是单一赋值、非命令式代码,因此如果您需要执行查找第一个设置位之类的操作,则不允许设置状态变量。
IF 0 THEN /*nothing*/
ELSE IF signal1 THEN
found := 1
ELSE IF signal2 THEN
found := 2
...
ELSE IF signal100 THEN
found := 100
ELSE
// nothing matched
ENDIF
想想看,这可能是我第一次遇到这种构造的地方。
顺便说一句,有些人对 if(0) 样式的反对意见——else-if 条件是顺序相关的,不能任意重新排序——不适用于 RTL 中的 AND 和 OR 和 XOR 逻辑——但确实适用于 short-电路 && 和 ||。
仅放置 if 块 1 有助于调试此块。这将禁用所有 if else 块功能。我们也可以扩展 if else 块。
Actually according to my opinion, if we put any variable for checking inside
e.g:-
public static void main(string args[])
{
var status;
var empList=_unitofWork.EmpRepository.Get(con=>con.isRetired==true);
//some code logic
if(empList.count>0)
{
status=true;
}
if(status)
{
//do something
}
else
{
//do something else
}
}
if then its dynamically get the value in run time and invoke the logic inside it, else its simply extra line of code i guess.
Anybody have any depth knowledge why this thing is used....or agree with me.
kindly respond.
例如,我已经看到这用于处理错误
if(0){
lable1:
//do something
}
if(0){
lable2:
//do something
}
.
.
and so on.
if(condition_fails)
goto lable1;
当 goto 用于管理错误时,这会很有帮助,语句仅在发生错误时执行。我在非常古老的 C 代码中看到了这一点(其中函数参数写在 '()' 之外),现在不要认为有人遵循这个。
我已经看过几次了,我认为最可能的原因是它正在评估代码的旧/不同版本/分支中的某些内容,或者可能用于调试,将其更改为 if(0)
是一种有点懒惰的删除方式不管那里有什么。
if
/else if
链不像决策树那样使用,而是作为“根据第一个匹配条件采取行动”的构造,其中恰好具有最高优先级的条件是t 特别“特别”。虽然我没有看到if(0)
被用作允许所有真实分支具有一致语法的一种方式,但我喜欢它所促进的一致语法。else if
行分成两部分并将预处理器保护放在中间。if (0)
分支并重新格式化其余的分支,使else
在自己的线上,并被沿#if TEST1_ENABLED && TEST2_ENABLED
线的守卫包围。