我们什么时候应该在C中使用断言?

Bru*_*uce 32 c

我在C中编写一个函数.作为一种风格问题,与返回错误代码相比,何时使用assert更好.让我们说这个功能正在划分两个数字.我应该断言除数是非零还是应该返回错误代码?如果可以,请提供更多示例,以区分清楚.

Fre*_*Foo 39

assert中止该过程,但在编译程序时变为无操作-DNDEBUG,因此它是一个相当粗略的调试工具,仅此而已.您应该只用于assert检查"不可能发生"的情况,例如违反算法的不变量或后置条件,但可能不会用于输入验证(当然不在库中).当检测到来自客户端的无效输入时,请友好并返回错误代码.

一个示例用法assert可能是:您已经实现了一个非常智能的排序算法,并且您想检查它是否真的排序.由于排序函数应该"正常工作",因此不返回值,因此无法在不更改API的情况下添加错误返回.

void sort(int *a, size_t n)
{
    recursive_super_duper_sort(a, 0, n);
    assert(is_sorted(a, n));
}

static bool is_sorted(int const *a, size_t n)
{
    for (size_t i=0; i<n-1; i++)
        if (a[i] > a[i+1])
            return false;

    return true;
}
Run Code Online (Sandbox Code Playgroud)

从长远来看,你真的想要一个适当的单元测试框架来代替这种东西assert,但它作为临时调试工具很有用.

  • @larsmans:更改了代码,以便`assert()`放在你做出断言的函数中; 如果你不同意这个因素,请随时回滚...... (2认同)

Ker*_* SB 17

错误代码表示运行时行为.断言是一种调试工具,允许开发人员声明他们对程序逻辑的假设确实是正确的.

它们是两个完全不同的东西,有不同的应用程序.

错误代码是正常程序流程的一部分.断言用于调试,如果触发断言,则表示您的程序编写不正确.


bob*_*mcr 14

通常,断言是程序员(即您)在将程序发布给真实用户之前发现逻辑/编程错误.断言不应用于检测运行时输入错误 - 请使用错误代码.


ibi*_*bid 8

这真的是品味问题.这是我的意见.

主要经验法则:断言失败始终是程序中的错误.

assert如果您希望调用者确保参数正确并且您想要指示任何其他行为是调用者中的错误,请使用an 来检查函数参数.除以零是IMO的一个很好的例子.

如果您希望调用者在调用之前无法确保参数正确,请使用错误代码.例如,事先检查参数可能在计算上非常昂贵.

切勿使用an assert检查用户输入.


dav*_*ink 8

传统的观点是使用assert()来帮助调试代码,以便在发生"不可能"的事情时发出警告.这个"警告"采取退出程序的形式.

我听说Jim Coplien(一般的C++大师和SCRUM培训师)主张让你的断言在部署的代码中保持活跃状态​​.(听起来很疯狂,我知道......)这是专门针对高可靠性服务器代码的.动机是,最好是失败,努力,让另一个节点接管,而不是容忍你的服务器处于"不可能"的状态.

(当然,跟踪失败并分析它们.这意味着存在错误或不正确的假设.)


Bas*_*tch 5

首先,可以禁用头文件中assert<assert.h>标题(例如,通过使用进行编译gcc -DNDEBUG),有时对于二进制文件的“生产”版本也可以将其禁用。

其次,如Linux手册页所述,

   The  purpose  of  this macro is to help the programmer find bugs in his
   program.   The  message  "assertion  failed  in  file  foo.c,  function
   do_bar(), line 1287" is of no help at all to a user.
Run Code Online (Sandbox Code Playgroud)

因此,assert仅在有故障的情况下才会失败。在特殊情况或错误情况下,您应该执行其他操作。

一些工具(甚至编译器)可能使用assert-ions来优化代码。

quotient函数示例中,assert如果确定在整个程序中使用的除数应该为非零(如果这样,则可以不同地命名函数,也许quotient_by_non_zero)就可以使用。如果您认为它可能发生,请使其成为致命消息,异常(例如,longjmp在C中),错误代码等。