275

我一直在学习 OpenCV 教程并遇到了这个assert功能;它有什么作用?

4

9 回答 9

323

assert如果它的参数被证明是假的,将终止程序(通常使用引用断言语句的消息)。它通常在调试过程中使用,以便在出现意外情况时使程序失败更加明显。

例如:

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() 和不保证做任何事情的组合来看,断言应该只用于测试开发人员假设的事情,而不是,例如,用户输入数字而不是字母(应该是其他方式处理)。

于 2009-10-15T09:51:28.627 回答
109

assert计算机语句类似于英语中的语句make sure

于 2009-10-15T11:02:30.453 回答
15

看一眼

C++ 中的 assert() 示例程序

许多编译器提供了一个 assert() 宏。如果它的参数评估为 TRUE,则 assert() 宏返回 TRUE,如果评估为 FALSE,则执行某种操作。许多编译器会在 assert() 失败时中止程序;其他人会抛出异常

assert() 宏的一个强大功能是,如果未定义 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
于 2009-10-15T09:51:27.633 回答
8

assert() 函数可以诊断程序错误。在 C 中,它被定义在 中<assert.h>,而在 C++ 中,它被定义在<cassert>. 它的原型是

void assert(int expression);

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

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

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

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

断言失败:x,文件 list19_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

错误信息:程序异常终止

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

于 2014-01-12T04:21:29.547 回答
4

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

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

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 compiler 数组在 32 位边界上对齐,因此编译器可以生成针对这种对齐方式的特定指令。

于 2009-10-15T10:29:39.663 回答
1

C++11 N3337 标准草案

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

19.3 断言

1 (表 42)中描述的头文件 <cassert> 提供了一个用于记录 C++ 程序断言的宏和一个禁用断言检查的机制。

2 内容与标准C 库头文件<assert.h> 相同。

C99 N1256标准草案

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

7.2 诊断 <assert.h>

1 标头<assert.h>定义了 assert 宏,并引用了另一个宏,NDEBUG该宏未由<assert.h>. 如果NDEBUG在包含 <assert.h> 的源文件中将其定义为宏名称,则断言宏被简单地定义为

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

每次 <assert.h>包含时,都会根据 NDEBUG 的当前状态重新定义断言宏。

2. assert 宏应该作为一个宏来实现,而不是一个实际的函数。如果为了访问实际函数而抑制宏定义,则行为未定义。

7.2.1 程序诊断

7.2.1.1 断言宏

概要

1.

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

描述

2 assert 宏将诊断测试放入程序中;它扩展为一个空表达式。执行时,如果表达式(应为标量类型)为假(即比较等于 0),则断言宏写入有关失败的特定调用的信息(包括参数的文本、源文件、源代码行号和封闭函数的名称——后者分别是实现定义格式的标准错误流上的预处理宏__FILE____LINE__标识符 的值。__func__165) 然后调用 abort 函数。

退货

3 断言宏不返回值。

于 2017-05-09T18:45:09.330 回答
1

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

  1. assert() 函数主要用于调试阶段,每次你想测试一个甚至可能不会在最终代码中出现的条件时,用 printf 语句编写 if else 是很乏味的。

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

  3. 当你在设计一个函数或一些代码时,assert() 会派上用场,并且想要了解代码将和不工作的限制,最后包括一个 if else 来评估它,基本上是在假设的情况下进行评估。

于 2019-04-08T22:50:57.267 回答
0

如果它评估的值为假,它会停止程序执行。通常它被一个宏包围,因此在使用发布设置编译时它不会被编译成生成的二进制文件。

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

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

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

您想要的理想是您可以在程序中出错,例如调用带有无效参数的函数,并且在它出现段错误(或无法按预期工作)之前命中断言

于 2009-10-15T09:55:34.573 回答
-5

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

代码示例:

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);
}
于 2016-04-14T13:04:48.397 回答