我的程序是用C语言编写的Linux,并且有许多函数具有不同的返回值模式:
1)一两次成功返回n
,失败时返回-1
2)有些人在成功时返回0
,在失败时返回-1
3)成功时返回1,失败时返回0(我通常使用布尔类型)
4)指针在失败时返回0
(我通常使用NULL
进行抛弃)。
我的混乱出现在前三个 - 返回指针的函数在失败时总是返回0
,这很容易。
第一个选项通常涉及返回长度的函数,该长度可能只是正数。
第二个选项,通常涉及命令行处理函数,但我不确定它是否正确,或许更好的值是EXIT_SUCCESS和EXIT_FAILURE?
第三个选项适用于在条件范围内调用方便且自然的函数,我通常使用int
值1和0来模拟布尔类型。
尽管这一切看似合情合理,但我仍然发现在创建函数时使用哪种样式或者在我希望使用它时使用哪种样式时,这些区域不是那么清晰或明显。
那么在决定返回类型时如何才能为我的方法增加清晰度呢?
答案 0 :(得分:4)
为什么不使用C标准库使用的方法?哦,等等......
答案 1 :(得分:4)
那么在决定返回类型时如何才能为我的方法增加清晰度呢?
每个返回类型选择一个模式并坚持下去,否则你会让自己疯狂。根据长期为平台建立的约定对模式建模:
如果要进行大量系统调用,则任何整数返回函数都应在失败时返回-1
。
如果您不进行系统调用,则可以自由地遵循C控制结构的约定,即非零意味着成功,零意味着失败。 (我不知道你为什么不喜欢bool
。)
如果函数返回指针,则应通过返回NULL
来指示失败。
如果函数返回浮点数,则应通过返回NaN来指示失败。
如果函数返回全范围的有符号和无符号整数,则可能不应该在返回值中编码成功或失败。
对C程序员来说,返回值的测试是一个祸害。如果失败很少并且您可以编写中央处理程序,请考虑使用可以使用longjmp
指示失败的exception macro package。
答案 2 :(得分:3)
不是您问题的实际答案,但您可能会发现一些有趣的随机评论:
通常很明显何时使用case(1),但是当涉及无符号类型时它会变得丑陋 - return (size_t)-1
仍然有效,但它不是很漂亮
如果您使用的是C99,使用_Bool
并没有错; imo,它比使用int
我在指针上下文(peronal偏好)中使用return NULL
而不是return 0
,但我很少检查它,因为我发现将指针视为布尔值更自然;一个常见的情况如下:
struct foo *foo = create_foo();
if(!foo) /* handle error */;
我尽量避免案例(2);使用EXIT_SUCCESS
和EXIT_FAILURE
可能是可行的,但是如果有两种以上可能的结果并且你将不得不使用enum
,那么这种方法才有意义
对于更复杂的程序,实现自己的错误处理方案可能是有意义的;有一些使用setjmp()
/ longjmp()
的相当高级的实现,但我更喜欢errno
的东西 - 就像不同类型的错误的不同变量一样
答案 3 :(得分:2)
我能想到上述方法失败的一个条件是一个可以返回任何值的函数,包括-1,比如添加两个有符号数的函数。
在那种情况下测试-1肯定是个坏主意。
如果出现故障,我最好以errno
的形式设置C标准提供的全局错误条件标志,并用它来处理错误。
虽然,C ++标准库提供了异常,这些异常为错误处理带来了很多困难。
答案 4 :(得分:2)
对于不能失败的确定性。是/否使用更具体(bool)返回类型的响应可以帮助保持一致性。为了更高级别的接口,可能需要考虑返回或更新特定于系统的消息传递/结果详细信息结构。
我希望0永远取得成功取决于以下想法:
零启用一些基本的分类,通过负面与正面的值来组织失败,例如完全失败和条件成功。我不建议这样做,因为它往往有点太浅而无法使用,并可能导致危险的行为假设。
当成功为零时,可以通过比较组的返回码,在一个条件下进行一系列正交调用并检查组成功。
rc = 0; rc + = func1(); rc + = func2(); rc + = func3(); if(rc == 0) 成功!
最重要的是,根据我的经验,零在使用标准库和第三方系统时似乎是成功的一致迹象。
答案 5 :(得分:0)
那么在决定返回类型时如何才能为我的方法增加清晰度呢?
事实上,你正在考虑这个问题还有很长的路要走。如果你提出一两条规则 - 如果它们有意义甚至更多(你可能需要不止一条规则 - 就像你提到的那样,你可能想要以不同于其他东西的方式处理返回的指针)我认为你会更好比许多商店。
我个人喜欢让0返回信号失败并且非零表示成功,但我没有强烈要求坚持这一点。我可以理解可能想要扭转这种感觉的哲学,以便你可以为失败找回不同的理由。
最重要的是要遵循指导原则。更好的是制定具有记录理由的指导原则(我相信,有理由的人更有可能遵循指导原则)。就像我说的那样,只是你正在考虑这些事情会让你领先于其他许多事情。
答案 6 :(得分:0)
这是一个偏好问题,但我注意到的是不一致。请考虑使用pre C99编译器
#define SUCCESS 1 #define ERROR 0
然后任何返回int的函数,返回一个或另一个以最大限度地减少混淆并虔诚地坚持它。再次,依赖于并考虑到开发团队,坚持他们的标准。
在C99之前的编译器中,int为零是false,任何大于零的都是true。这取决于你的编译器是什么标准,如果它是C99,请使用stdbool的_Bool类型。
C的最大优势是你可以使用你的个人风格,但是在需要团队努力的情况下,坚持团队的标准并且虔诚地遵循它,即使你离开那份工作,另一位程序员将会感激你。
并保持一致。
希望这有帮助, 最好的祝福, 汤姆。
答案 7 :(得分:0)
大多数C标准库使用策略仅在成功时返回true(或1),在失败时返回false(或0),并将结果存储在传入的位置。比“失败”更具体的错误代码存储在特殊变量errno中。
类似于int add(int* result, int a, int b)
的东西,它在*结果中存储+ b并返回1(或返回0并将errno设置为合适的值,例如,如果+ b恰好大于maxint)。