关于c ++:什么是“断言”功能?

What is the “assert” function?

我一直在学习opencv教程,遇到了assert函数;它有什么作用?


如果其参数被证明是错误的,assert将终止程序(通常带有一条引用assert语句的消息)。它通常在调试期间使用,以使程序在发生意外情况时更明显地失败。

例如:

1
assert(length >= 0);  // die if length is negative.

如果失败,您还可以添加一条信息更丰富的消息来显示:

1
assert(length >= 0 &&"Whoops, length can't possibly be negative! (didn't we just check 10 lines ago?) Tell jsmith");

或者像这样:

1
assert(("Length can't possibly be negative! Tell jsmith", length >= 0));

在进行发布(非调试)构建时,还可以通过定义NDEBUG宏(通常使用编译器开关)来消除评估assert语句的开销。其推论是,您的程序不应该依赖于所运行的断言宏。

1
2
3
4
5
6
7
8
9
10
11
12
13
// BAD
assert(x++);

// GOOD
assert(x);    
x++;

// Watch out! Depends on the function:
assert(foo());

// Here's a safer way:
int ret = foo();
assert(ret);

从调用abort()的程序的组合来看,断言只应用于测试开发人员假定的东西,而不是用户输入数字而不是字母(应该通过其他方式处理)。


assert computer语句类似于确保使用英语的语句。


看一看

C++中的实例程序

Many compilers offer an assert()
macro. The assert() macro returns TRUE
if its parameter evaluates TRUE and
takes some kind of action if it
evaluates FALSE. Many compilers will
abort the program on an assert() that
fails; others will throw an exception

One powerful feature of the assert()
macro is that the preprocessor
collapses it into no code at all if
DEBUG is not defined. It is a great
help during development, and when the
final product ships there is no
performance penalty nor increase in
the size of the executable version of
the program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include

void analyze (char *, int);

int main(void)
{
   char *string ="ABC";
   int length = 3;

   analyze(string, length);
   printf("The string %s is not null or empty,"
         "and has length %d
"
, string, length);
}

void analyze(char *string, int length)
{
   assert(string != NULL);     /* cannot be NULL */
   assert(*string != '\0');    /* cannot be empty */
   assert(length > 0);         /* must be positive */
}

/****************  Output should be similar to  ******************
The string ABC is not null or empty, and has length 3


函数的作用是:诊断程序错误。它在中定义,其原型是

1
void assert(int expression);

参数表达式可以是您想要测试的任何东西——变量或任何C表达式。如果表达式的计算结果为true,则assert()不执行任何操作。如果表达式的计算结果为false,则assert()将在stderr上显示错误消息并中止程序执行。

如何使用assert()?它最常用于跟踪程序错误(与编译错误不同)。错误不会阻止程序编译,但会导致程序给出错误的结果或运行不正确(例如锁定)。例如,您正在编写的财务分析程序可能偶尔会给出错误的答案。您怀疑问题是由可变利率呈现负值引起的,这种情况永远不会发生。要检查这个,请放置语句

断言(利率大于等于0);在程序中使用利率的位置。如果该变量确实变为负数,那么assert()宏将提醒您。然后,您可以检查相关代码以找到问题的原因。

要查看assert()的工作原理,请运行下面的示例程序。如果输入非零值,程序将显示该值并正常终止。如果输入零,assert()宏将强制异常程序终止。您看到的确切错误消息将取决于您的编译器,但下面是一个典型示例:

断言失败:x,文件列表19_3.c,第13行注意,为了使assert()工作,必须在调试模式下编译程序。有关启用调试模式的信息,请参阅编译器文档(稍后解释)。稍后在发布模式下编译最终版本时,将禁用assert()宏。

1
2
3
4
5
6
7
8
9
10
11
 int x;

 printf("
Enter an integer value:"
);
 scanf("%d", &x);

 assert(x >= 0);

 printf("You entered %d.
"
, x);
 return(0);

输入整数值:10

你进了10。

输入整数值:-1

错误信息:异常程序终止

您的错误消息可能会有所不同,这取决于您的系统和编译器,但总体思路是相同的。


对于大多数编译器来说,诸如"引发异常"和"停止执行"之类的东西可能是正确的,但不是全部。(BTW,是否存在确实抛出异常的断言语句?)

这是C6X和其他TI编译器使用的断言的一个有趣的稍微不同的含义:当看到某些断言语句时,这些编译器使用该语句中的信息来执行某些优化。邪恶的

C中的例子:

1
2
3
4
5
6
7
8
9
10
11
12
int dot_product(short *x, short *y, short z)
{
  int sum = 0
  int i;

  assert( ( (int)(x) & 0x3 ) == 0 );
  assert( ( (int)(y) & 0x3 ) == 0 );

  for( i = 0 ; i < z ; ++i )
    sum += x[ i ] * y[ i ];
  return sum;
}

这告诉反编译器数组是在32位边界上对齐的,因此编译器可以生成针对这种对齐方式的特定指令。


C++ 11 N33标准草案

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n337.pdf

19.3断言

1 The header , described in (Table 42), provides a macro for documenting C ++ program assertions
and a mechanism for disabling the assertion checks.

2 The contents are the same as the Standard C library header .

C99 N1256标准草案

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf

7.2诊断

1 The header defines the assert macro and refers to another macro, NDEBUG which is not defined by . If NDEBUG is defined as a macro name at the
point in the source file where is included, the assert macro is defined simply as

1
 #define assert(ignore) ((void)0)

The assert macro is redefined according to the current state of NDEBUG each time that
is included.

2.
The assert macro shall be implemented as a macro, not as an actual function. If the
macro definition is suppressed in order to access an actual function, the behavior is
undefined.

7.2.1程序诊断

7.2.1.1断言宏

Synopsis

1.

1
2
#include
void assert(scalar expression);

Description

2
The assert macro puts diagnostic tests into programs; it expands to a void expression.
When it is executed, if expression (which shall have a scalar type) is false (that is,
compares equal to 0), the assert macro writes information about the particular call that
failed (including the text of the argument, the name of the source file, the source line
number, and the name of the enclosing function — the latter are respectively the values of
the preprocessing macros __FILE__ and __LINE__ and of the identifier
__func__) on the standard error stream in an implementation-defined format. 165) It
then calls the abort function.

Returns

3
The assert macro returns no value.


在普通if else和printf上使用assert()函数有三个主要原因

  • AsvestTo()函数主要用于调试阶段,如果您想测试一个甚至在最终代码中都无法实现的条件,那么如果用PROTF语句编写其他文件是很乏味的。

  • 在大型软件部署中,AsScript非常方便,您可以让编译器在使用AsHeST()函数头文件之前定义的NDebug宏忽略AsScript语句。

  • 当你设计一个函数或一些代码时,AsvestTo()会很方便,并且想知道代码会有什么限制而不能工作,最后包括一个IF要件来评估它基本上是在假设。


  • 它是一个函数,如果它计算的值为假,它将停止程序执行。通常它被一个宏包围,这样在用发布设置编译时就不会编译成结果二进制文件。

    它设计用于测试您所做的假设。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    void strcpy(char* dest, char* src){
        //pointers shouldn't be null
        assert(dest!=null);
        assert(src!=null);

        //copy string
        while(*dest++ = *src++);
    }

    理想的情况是,您可以在程序中出错,比如调用带有无效参数的函数,并在断言出现错误之前命中断言(或未能按预期工作)。


    断言允许您在条件(断言)为假时停止执行。

    例如(伪代码):

    1
    2
    3
    4
    5
    Bank myBank = Bank.GetMyStuff();

    assert(myBank != NULL);

    // .. Continue.

    如果mybank为空,函数将停止执行,并产生错误。这对于使某些可重用代码接受正确的条件等非常有用。


    此外,您可以使用它来检查动态分配是否成功。

    代码示例:

    1
    2
    3
    4
    5
    6
    7
    8
    int ** p;
    p = new int * [5];      // Dynamic array (size 5) of pointers to int
    for (int i = 0; i < 5; ++i) {
        p[i] = new int[3]; // Each i(ptr) is now pointing to a dynamic
                           // array (size 3) of actual int values
    }

    assert (p);            // Check the dynamic allocation.

    类似:

    1
    2
    3
    4
    if (p == NULL) {
        cout <<"dynamic allocation failed" << endl;
        exit(1);
    }