什么是“断言”功能?

时间:2009-10-15 09:48:00

标签: c++ c assert

我一直在研究OpenCV教程并遇到了assert函数;它做了什么?

10 个答案:

答案 0 :(得分:267)

assert将终止程序(通常使用引用assert语句的消息),如果其参数结果为false。它通常在调试期间用于在发生意外情况时使程序更加明显失败。

例如:

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

如果失败,您还可以添加更多信息,以便显示:

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

或者像这样:

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

当您进行发布(非调试)构建时,您还可以通过定义assert宏(通常使用编译器开关)来消除评估NDEBUG语句的开销。这样做的必然结果是你的程序永远不会依赖于运行的断言宏。

// 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()的程序和不保证执行任何操作的组合中,断言应仅用于测试开发人员所假设的内容,而不是用户输入数字而不是字母(应该通过其他方式处理)。

答案 1 :(得分:104)

断言计算机声明类似于英语中确保的声明。

答案 2 :(得分:13)

看看

assert() example program in C++

  

许多编译器都提供了一个断言()   宏。 assert()宏返回TRUE   如果它的参数计算为TRUE和   如果它采取某种行动   评估错误。许多编译器都会   在断言()上中止该程序   失败;其他人会抛出异常

     

断言()的一个强大功能   宏是那个预处理器   如果将它折叠成没有代码的话   DEBUG没有定义。这太好了   在开发过程中提供帮助的时候   最终产品船没有   绩效惩罚也没有增加   可执行版本的大小   该计划。

例如

#include <stdio.h>
#include <assert.h>

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 \n", 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

答案 3 :(得分:6)

assert()函数可以诊断程序错误。它在<assert.h>中定义,其原型是

void assert(int expression);

参数表达式可以是您要测试的任何内容 - 变量或任何C表达式。如果expression的计算结果为TRUE,则assert()不执行任何操作。如果expression的计算结果为FALSE,则assert()会在stderr上显示错误消息并中止程序执行。

你如何使用assert()?它最常用于追踪程序错误(与编译错误不同)。错误不会阻止程序编译,但会导致程序输出错误或运行不正确(例如锁定)。例如,您正在编写的财务分析程序可能偶尔会给出错误的答案。你怀疑这个问题是由变量interest_rate带来负值引起的,这个值应该永远不会发生。要检查这一点,请放置语句

断言(interest_rate&gt; = 0); 在程序中使用interest_rate的位置。如果变量确实变为负数,则assert()宏会提醒您。然后,您可以检查相关代码以找出问题的原因。

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

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

 int x;

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

 assert(x >= 0);

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

输入一个整数值:10

你输了10。

输入一个整数值:-1

错误讯息: 异常程序终止

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

答案 4 :(得分:4)

对于大多数编译器来说,像'引发异常'和'暂停执行'这样的东西可能都是如此,但对所有编译器都不是。 (顺便说一句,是否存在真正抛出异常的断言语句?)

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

C:

中的示例
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;
}

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

答案 5 :(得分:1)

C ++ 11 N3337标准草案

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

19.3断言

  

1(表42)中描述的标题&lt; cassert&gt;提供了一个用于记录C ++程序断言的宏   以及禁用断言检查的机制。

     

2内容与标准C库标题&lt; assert.h&gt;相同。

C99 N1256标准草案

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

7.2诊断&lt; assert.h&gt;

  

1标题<assert.h>定义断言宏,并引用另一个宏NDEBUG,它不是由<assert.h>定义的。如果NDEBUG被定义为宏名称   在源文件中指向&lt; assert.h&gt;包含,断言宏简单定义为

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

每次根据NDEBUG的当前状态重新定义断言宏   <assert.h>已包含在内。

     

2。   断言宏应实现为宏,而不是实际功能。如果   为了访问实际函数,宏定义被抑制,行为是   未定义。

7.2.1程序诊断

7.2.1.1断言宏

  

概要

     

1

#include <assert.h>
void assert(scalar expression);
     

描述

     

2   断言宏将诊断测试放入程序中;它扩展为void表达式。   执行时,如果表达式(应具有标量类型)为false(即,   比较等于0),断言宏写入有关特定呼叫的信息   失败(包括参数的文本,源文件的名称,源代码行   number和封闭函数的名称 - 后者分别是值的值   预处理宏__FILE____LINE__以及标识符   __func__)在实现定义格式的标准错误流上。 165)它   然后调用中止函数。

     

返回

     

3   断言宏不返回任何值。

答案 6 :(得分:0)

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

例如(Pseudocode):

Bank myBank = Bank.GetMyStuff();

assert(myBank != NULL);

// .. Continue.

如果myBank为NULL,则该函数将停止执行,并产生错误。这非常适合使某些可重用代码接受正确的条件等。

答案 7 :(得分:0)

如果已评估的值为false,则该函数将暂停程序执行。通常它被宏包围,因此在使用发布设置进行编译时不会将其编译为结果二进制文件。

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

void strcpy(char* dest, char* src){
    //pointers shouldn't be null
    assert(dest!=null);
    assert(src!=null);

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

你想要的理想是你可以在你的程序中出错,比如调用一个带有无效参数的函数,然后在它出现段错误之前点击一个断言(或者无法按预期工作)

答案 8 :(得分:0)

在其他情况下使用assert()函数和printf的主要原因有三个:

  1. assert()函数主要在调试阶段使用,每次要测试条件(甚至可能不会在最终代码中使用)时,都用printf语句编写是否麻烦。 p>

  2. 在大型软件部署中,assert非常方便,您可以在为assert()函数链接头文件之前使用定义的NDEBUG宏使编译器忽略assert语句。

  3. assert()在您设计函数或某些代码时想要方便的使用,以使您知道什么限制代码将无法正常工作,并最终包含一个if评估(基本上是在假设条件下进行评估)的想法。

答案 9 :(得分:-4)

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

代码示例:

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.

类似于:

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