我一直在学习 OpenCV 教程并遇到了这个assert
功能;它有什么作用?
9 回答
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() 和不保证做任何事情的组合来看,断言应该只用于测试开发人员假设的事情,而不是,例如,用户输入数字而不是字母(应该是其他方式处理)。
assert计算机语句类似于英语中的语句make sure。
看一眼
许多编译器提供了一个 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
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
错误信息:程序异常终止
您的错误消息可能会有所不同,具体取决于您的系统和编译器,但总体思路是相同的。
对于大多数编译器来说,像“引发异常”和“停止执行”这样的东西可能是正确的,但并非对所有编译器都是如此。(顺便说一句,是否存在真正引发异常的断言语句?)
这是 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 位边界上对齐,因此编译器可以生成针对这种对齐方式的特定指令。
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 断言宏不返回值。
使用 assert() 函数而不是普通 if else 和 printf 有三个主要原因
assert() 函数主要用于调试阶段,每次你想测试一个甚至可能不会在最终代码中出现的条件时,用 printf 语句编写 if else 是很乏味的。
在大型软件部署中,assert 非常方便,您可以使用在链接 assert() 函数的头文件之前定义的 NDEBUG 宏使编译器忽略 assert 语句。
当你在设计一个函数或一些代码时,assert() 会派上用场,并且想要了解代码将和不工作的限制,最后包括一个 if else 来评估它,基本上是在假设的情况下进行评估。
如果它评估的值为假,它会停止程序执行。通常它被一个宏包围,因此在使用发布设置编译时它不会被编译成生成的二进制文件。
它旨在用于测试您所做的假设。例如:
void strcpy(char* dest, char* src){
//pointers shouldn't be null
assert(dest!=null);
assert(src!=null);
//copy string
while(*dest++ = *src++);
}
您想要的理想是您可以在程序中出错,例如调用带有无效参数的函数,并且在它出现段错误(或无法按预期工作)之前命中断言
此外,您可以使用它来检查动态分配是否成功。
代码示例:
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);
}