在C中编程好几年后,我意识到我一直忽略了从函数返回零来表示成功的C约定。这个惯例对我来说在语义上是错误的,因为零当然是错误的。问题是我喜欢命名像is_valid_foobar()
这样的函数,为了适应'虚假意味着成功'的惯例,我必须更加模糊......
而不是:
if ( ! is_valid_foobar() ) {
return (error);
}
其他程序员写道:
if ( validate_foobar() ) {
return (error);
}
我的实现如下:
int is_valid_foobar (int foobar ) {
if ( foobar < MAX_ALLOWED ) {
return TRUE;
}
return FALSE;
}
在代码审查中,我实际上并未发现任何问题。所以我认为这不是一个可怕的习惯,但它是“非常规的”。我很好奇人们的想法。
我对我为函数和变量名做出的选择非常谨慎,典型的评论评论是“代码非常清晰”,而且根本不需要输入额外的{{ {1}}在函数调用的前面。但是,你怎么说,哦,强大的S.O?
答案 0 :(得分:19)
我说两者都是正确的,出于不同的目的:
如果您正在执行简单的go / no-go验证,例如is_numeric(),然后true和false很好地工作。
对于更精细的内容,0 ==成功范例是有用的,因为它允许返回多个错误条件。
在这种情况下,调用者可以简单地对0进行测试,或者检查非0返回以获得更具体的失败解释。例如文件打开调用可能由于不存在,权限不足等原因而失败。
答案 1 :(得分:11)
这个惯例并不完全是你想象的。进程应以0状态退出以指示成功,而返回错误代码的函数通常使用0来表示“无错误”。但作为布尔值,0应该表示false,非零表示true。要使用0表示布尔值,有一天你可以登上The Daily WTF。
答案 2 :(得分:6)
我编程C已经有一段时间了,但我认为你在谈论两种不同的功能:
is_foo
是一个函数,用于检查某些属性foo并返回0
(false
)或非 - 0
(true
)以指示布尔值该财产的价值。调用这些函数时,不会出现错误状态(如果发生错误状态,则会映射到其中一个值)。foo
是执行动作foo的函数。它会在成功时返回0
,在错误时返回非0
值。答案 3 :(得分:3)
我不确定我是否同意“从函数返回零以表示成功”的约定。
AFAIK,惯例是零是假的,并且在谓词的情况下所有非零都是真的。
但是,此约定仅适用于返回布尔值的明显谓词(例如,true / false)。如果函数的主要目标不是返回布尔值(例如,printf,fopen等),则返回值用于指示失败原因,然后您可以采用UNIX约定“silent或0”除非有一个问题“。
对于返回值,使用固定返回值没有任何问题,它使一切更加方便。
很大的风险,恕我直言,许多人声明他们自己的常量,当其他人使用相同的文件时,你开始与他们自己的常量发生冲突。所以你的TRUE / FALSE与其他人的TRUE / FALSE相冲突。
答案 4 :(得分:3)
特别是当您将函数命名为is_foo()时,标准C字符函数(isdigit(),isupper()等)是您按照自己的方式进行操作的良好先例。
答案 5 :(得分:3)
C没有布尔的概念,除了0是假的,其他任何东西都是真的。
返回0的想法来自于返回代码,指示失败是什么。如果你没有做返回码,那么将1和0视为真和假是没有错的。毕竟,TRUE和FALSE只是1和0的typedef。
这应该有详细记录,你的函数注释应该说明确“返回TRUE或FALSE”。
你也可以编写if(is_invalid_foobar()),这可以使语句易于理解并且在语义上仍然正确。
答案 6 :(得分:2)
这不是一个像UN * X shell那样的C约定。考虑标准C iasalpha(),isdigit()等函数。它们都返回非零值表示成功。底线:在C'中'是'非零。
答案 7 :(得分:0)
如果它烧伤你,那就太糟糕了。如果你从来没有追查任何错误,我会说你没事。更重要的是,函数上面的注释以“为...返回零”
开头在尝试说出为什么以及错误标志时,会使用“非零是错误”约定。
答案 8 :(得分:0)
对我来说,实际检查0看起来更自然,编译器无论如何都要对它进行优化,所以我想写例如
if(check_foo == 0) //做点什么
答案 9 :(得分:0)
按函数返回值 - True和False的约定或成功和错误:
答案 10 :(得分:0)
返回1或0仍然是完全随意的。只要保持一致,如果有错误代码,至少要评论它们在某处的含义。