什么时候在C中使用断言?

时间:2022-09-11 11:41:25

I am writing a function in C. As a matter of style, when is it good to use assert compared to returning an error code. Lets say the function is dividing two numbers. Should I assert the divisor be non-zero or should I return an error code? Please give more examples, if you can, to make the distinction clear.

我在c语言中编写一个函数,这是一种风格的问题,与返回错误代码相比,使用assert是什么时候呢?我们说函数是除以两个数。我应该断言除数是非零的,还是应该返回一个错误码?如果可以的话,请给出更多的例子,以明确区别。

8 个解决方案

#1


36  

assert aborts the process, but is turned into a no-op when the program is compiled with -DNDEBUG, so it's a rather crude debugging tool and nothing more than that. You should only use assert to check for situations that "can't happen", e.g. that violate the invariants or postconditions of an algorithm, but probably not for input validation (certainly not in libraries). When detecting invalid input from clients, be friendly and return an error code.

assert中止了进程,但是当程序用-DNDEBUG编译时,它就变成了一个禁止操作,所以这是一个相当粗糙的调试工具,除此之外没有别的。您应该只使用assert检查“不可能发生”的情况,例如违反算法的不变量或后置条件,但可能不用于输入验证(当然不在库中)。当检测到来自客户端的无效输入时,请友好地返回错误代码。

An example use of assert could be: you've implemented an incredibly smart sorting algorithm and you want to check whether it really sorts. Since the sorting function is supposed to "just work" and therefore doesn't return a value, you can't add error returns without changing the API.

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;
}

In the long run, you'd really want a proper unit testing framework for this kind of thing instead of assert, but it's useful as a temporary debugging tool.

从长远来看,您确实需要一个合适的单元测试框架,而不是断言,但它作为临时调试工具非常有用。

#2


17  

An error code signals runtime behaviour. An assertion is a debugging tool that allows the developer to assert that her assumptions about the program logic are indeed true.

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

They're two completely different things with different applications.

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

Error codes are part of your normal program flow. Assertions are only for debugging, and if an assertion is triggered, that means that your program is not written correctly.

错误代码是正常程序流的一部分。断言仅用于调试,如果一个断言被触发,这意味着您的程序没有被正确地编写。

#3


13  

In general, asserts are for the programmer (i.e. you) to find logic/programming errors before releasing the program to real users. Asserts should not be used for detecting runtime input errors -- use error codes for these.

通常,断言是指程序员(即您)在将程序发布给实际用户之前找到逻辑/编程错误。断言不应该用于检测运行时输入错误——对这些错误使用错误代码。

#4


8  

This is really a matter of taste. Here is my opinion.

这确实是个趣味问题。这是我的意见。

The main rule of thumb: an assertion failure is always a bug in the program.

经验的主要规则:断言失败始终是程序中的一个错误。

Use an assert to check function parameters if you expect the caller to ensure that the argument is correct and you want to indicate that any other behavior is a bug in the caller. Dividing by zero is, IMO, a very good example.

如果希望调用方确保参数是正确的,并且希望表明调用方中的任何其他行为是错误的,则使用assert检查函数参数。除以0是一个很好的例子。

Use an error code if you expect the caller not to be able to ensure that the argument is correct before calling. For example, it could be very computationally expensive to check the arguments beforehand.

如果您希望调用者在调用之前不能确保参数是正确的,请使用错误代码。例如,预先检查参数的计算开销可能非常大。

Never use an assert to check user input.

不要使用断言检查用户输入。

#5


8  

The conventional wisdom is to use assert() to help debug your code, to warn you when something "impossible", something that must not happen, has happened. This "warning" takes the form of exiting your program.

传统的智慧是使用assert()来帮助调试代码,当发生“不可能”的事情(一定不会发生的事情)时发出警告。这个“警告”以退出程序的形式出现。

I've heard Jim Coplien (general C++ guru and SCRUM trainer) advocate leaving your asserts active in deployed code. (It sounds crazy, I know...) This was specifically for high-reliability server code. The motivation was that it's better to fail, hard, and let another node take over, than to tolerate your server being in an "impossible" state.

我听说过Jim Coplien(通用c++大师和SCRUM培训师)主张在部署代码中保持活跃。(听起来很疯狂,我知道……)这是专门针对高可靠性服务器代码的。其动机是,与其容忍服务器处于“不可能”的状态,不如让另一个节点接管。

(And of course, track the failures, and analyze them. It means there is a bug or incorrect assumption.)

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

#6


4  

First, assert from the <assert.h> header can be disabled (e.g. by compiling with gcc -DNDEBUG), and sometimes is disabled for the "production" version of a binary.

首先,从 头可以被禁用(例如,通过使用gcc -DNDEBUG编译),有时为二进制版本的“生产”版本禁用。 断言。h>

Second, as stated by Linux man page,

第二,如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.

So assert should fail only in buggy situations. In exceptional or error situations, you should do something else.

所以断言应该只在错误的情况下才会失败。在异常或错误的情况下,您应该做一些其他的事情。

Some tools (or even compilers) might use assert-ions to e.g. optimize your code.

有些工具(甚至编译器)可能会使用断言离子来优化代码。

In your example of a quotient function, you'll use assert if, inside your entire program, you are sure that the divisor should be non-zero (but then it could make sense to name the function differently, perhaps quotient_by_non_zero). If you consider that it could happen, make it a fatal message, an exception (i.e. longjmp in C), an error code, etc.

在您的商函数示例中,您将使用assert if,在整个程序中,您确定除数应该是非零的(但是,可以使用不同的名称来命名函数,也许可以使用commonent_by_non_zero)。如果您认为它可能发生,请将它设置为致命消息、异常(例如C中的longjmp)、错误代码等。

#7


3  

Since C does not support exceptions you don't have any real option other than to return an error code. A failing C assert() results in abort() being called which bombs the process. That's not really comparable with standard error handling.

由于C不支持异常,所以除了返回错误代码之外,您没有任何实际的选项。失败的C assert()导致调用abort(),从而导致进程失败。这与标准错误处理没有可比性。

For floating point operations you can use NaN to signal error conditions. For integer operations an error code is simply your only option.

对于浮点运算,您可以使用NaN来表示错误条件。对于整数操作,错误代码只是您的惟一选项。

#8


2  

Use an assert when your program meets a situation that does not allow to continue. Assertions are a 'contract' and I use them as a 'contract' with OS and situation 'danger in delay'.

当程序遇到不允许继续的情况时,使用assert。断言是一种“契约”,我将其作为与操作系统的“契约”和“延迟的危险”。

In order to emulate exceptions you can still use GOTO 'ERRORLABEL' and terminate clean after running a clean up function.

为了模拟异常,您仍然可以使用GOTO 'ERRORLABEL'并在运行clean up函数之后终止clean。

#1


36  

assert aborts the process, but is turned into a no-op when the program is compiled with -DNDEBUG, so it's a rather crude debugging tool and nothing more than that. You should only use assert to check for situations that "can't happen", e.g. that violate the invariants or postconditions of an algorithm, but probably not for input validation (certainly not in libraries). When detecting invalid input from clients, be friendly and return an error code.

assert中止了进程,但是当程序用-DNDEBUG编译时,它就变成了一个禁止操作,所以这是一个相当粗糙的调试工具,除此之外没有别的。您应该只使用assert检查“不可能发生”的情况,例如违反算法的不变量或后置条件,但可能不用于输入验证(当然不在库中)。当检测到来自客户端的无效输入时,请友好地返回错误代码。

An example use of assert could be: you've implemented an incredibly smart sorting algorithm and you want to check whether it really sorts. Since the sorting function is supposed to "just work" and therefore doesn't return a value, you can't add error returns without changing the API.

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;
}

In the long run, you'd really want a proper unit testing framework for this kind of thing instead of assert, but it's useful as a temporary debugging tool.

从长远来看,您确实需要一个合适的单元测试框架,而不是断言,但它作为临时调试工具非常有用。

#2


17  

An error code signals runtime behaviour. An assertion is a debugging tool that allows the developer to assert that her assumptions about the program logic are indeed true.

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

They're two completely different things with different applications.

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

Error codes are part of your normal program flow. Assertions are only for debugging, and if an assertion is triggered, that means that your program is not written correctly.

错误代码是正常程序流的一部分。断言仅用于调试,如果一个断言被触发,这意味着您的程序没有被正确地编写。

#3


13  

In general, asserts are for the programmer (i.e. you) to find logic/programming errors before releasing the program to real users. Asserts should not be used for detecting runtime input errors -- use error codes for these.

通常,断言是指程序员(即您)在将程序发布给实际用户之前找到逻辑/编程错误。断言不应该用于检测运行时输入错误——对这些错误使用错误代码。

#4


8  

This is really a matter of taste. Here is my opinion.

这确实是个趣味问题。这是我的意见。

The main rule of thumb: an assertion failure is always a bug in the program.

经验的主要规则:断言失败始终是程序中的一个错误。

Use an assert to check function parameters if you expect the caller to ensure that the argument is correct and you want to indicate that any other behavior is a bug in the caller. Dividing by zero is, IMO, a very good example.

如果希望调用方确保参数是正确的,并且希望表明调用方中的任何其他行为是错误的,则使用assert检查函数参数。除以0是一个很好的例子。

Use an error code if you expect the caller not to be able to ensure that the argument is correct before calling. For example, it could be very computationally expensive to check the arguments beforehand.

如果您希望调用者在调用之前不能确保参数是正确的,请使用错误代码。例如,预先检查参数的计算开销可能非常大。

Never use an assert to check user input.

不要使用断言检查用户输入。

#5


8  

The conventional wisdom is to use assert() to help debug your code, to warn you when something "impossible", something that must not happen, has happened. This "warning" takes the form of exiting your program.

传统的智慧是使用assert()来帮助调试代码,当发生“不可能”的事情(一定不会发生的事情)时发出警告。这个“警告”以退出程序的形式出现。

I've heard Jim Coplien (general C++ guru and SCRUM trainer) advocate leaving your asserts active in deployed code. (It sounds crazy, I know...) This was specifically for high-reliability server code. The motivation was that it's better to fail, hard, and let another node take over, than to tolerate your server being in an "impossible" state.

我听说过Jim Coplien(通用c++大师和SCRUM培训师)主张在部署代码中保持活跃。(听起来很疯狂,我知道……)这是专门针对高可靠性服务器代码的。其动机是,与其容忍服务器处于“不可能”的状态,不如让另一个节点接管。

(And of course, track the failures, and analyze them. It means there is a bug or incorrect assumption.)

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

#6


4  

First, assert from the <assert.h> header can be disabled (e.g. by compiling with gcc -DNDEBUG), and sometimes is disabled for the "production" version of a binary.

首先,从 头可以被禁用(例如,通过使用gcc -DNDEBUG编译),有时为二进制版本的“生产”版本禁用。 断言。h>

Second, as stated by Linux man page,

第二,如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.

So assert should fail only in buggy situations. In exceptional or error situations, you should do something else.

所以断言应该只在错误的情况下才会失败。在异常或错误的情况下,您应该做一些其他的事情。

Some tools (or even compilers) might use assert-ions to e.g. optimize your code.

有些工具(甚至编译器)可能会使用断言离子来优化代码。

In your example of a quotient function, you'll use assert if, inside your entire program, you are sure that the divisor should be non-zero (but then it could make sense to name the function differently, perhaps quotient_by_non_zero). If you consider that it could happen, make it a fatal message, an exception (i.e. longjmp in C), an error code, etc.

在您的商函数示例中,您将使用assert if,在整个程序中,您确定除数应该是非零的(但是,可以使用不同的名称来命名函数,也许可以使用commonent_by_non_zero)。如果您认为它可能发生,请将它设置为致命消息、异常(例如C中的longjmp)、错误代码等。

#7


3  

Since C does not support exceptions you don't have any real option other than to return an error code. A failing C assert() results in abort() being called which bombs the process. That's not really comparable with standard error handling.

由于C不支持异常,所以除了返回错误代码之外,您没有任何实际的选项。失败的C assert()导致调用abort(),从而导致进程失败。这与标准错误处理没有可比性。

For floating point operations you can use NaN to signal error conditions. For integer operations an error code is simply your only option.

对于浮点运算,您可以使用NaN来表示错误条件。对于整数操作,错误代码只是您的惟一选项。

#8


2  

Use an assert when your program meets a situation that does not allow to continue. Assertions are a 'contract' and I use them as a 'contract' with OS and situation 'danger in delay'.

当程序遇到不允许继续的情况时,使用assert。断言是一种“契约”,我将其作为与操作系统的“契约”和“延迟的危险”。

In order to emulate exceptions you can still use GOTO 'ERRORLABEL' and terminate clean after running a clean up function.

为了模拟异常,您仍然可以使用GOTO 'ERRORLABEL'并在运行clean up函数之后终止clean。