什么是断言?你为什么要使用它们?

Posted

技术标签:

【中文标题】什么是断言?你为什么要使用它们?【英文标题】:What are assertions? and why would you use them? 【发布时间】:2008-10-31 11:28:32 【问题描述】:

如何在 C++ 中完成断言?示例代码表示赞赏。

【问题讨论】:

【参考方案1】:

断言是一种明确检查代码所做假设的方法,它可以帮助您通过缩小可能出现的问题来追踪大量错误。它们通常只在您的应用程序的特殊“调试”版本中进行评估,因此它们不会减慢最终发布版本的速度。

假设您编写了一个将指针作为参数的函数。您的代码很有可能会假定指针是非 NULL 的,那么为什么不使用断言显式检查呢?方法如下:

#include <assert.h>

void function(int* pointer_arg)

    assert(pointer_arg != NULL);

    ...

需要注意的重要一点是,您断言的表达式绝不能有副作用,因为它们不会出现在发布版本中。所以永远不要做这样的事情:

assert(a++ == 5);

有些人还喜欢在他们的断言中添加一些小信息来帮助赋予他们意义。由于字符串总是评估为真,你可以这样写:

assert((a == 5) && "a has the wrong value!!");

【讨论】:

我以前没见过带字符串的 anding。真的很有用! 在 Perl 领域一直使用这种技巧(或类似的变体),即使用给出的示例:a == 5 || die("a 的值错误");为松散的布尔输入欢呼。 这个字符串的另一个技巧是在发布代码中验证值,但在调试代码中断言。例如,首先使用 if(x>10) 检查,然后如果错误条件通过,则只需 assert(!"x out of bounds") 然后打印到日志文件等。 @David:通常断言语句会在失败时打印失败条件以及文件/行信息。因此,它为您提供的是人类可读的信息以及实际信息。等效地,您可以使用两个参数编写自己的断言:条件和消息。 David,您的 IDE 通常会在向您显示的错误消息中显示失败的表达式,因此如果您的表达式包含字符串,则会弹出【参考方案2】:

断言是布尔表达式,通常应该始终为真。

它们用于确保您所期望的也会发生。

void some_function(int age)

     assert(age > 0);

你编写了处理年龄的函数,你也“知道”你总是在传递合理的参数,然后你使用了一个断言。这就像说“我知道这永远不会出错,但如果真的出错了,我想知道”,因为,嗯,每个人都会犯错误。

所以不要检查合理的用户输入,如果有可能出现问题的场景,不要使用断言。进行真正的检查并处理错误。

断言通常仅用于调试构建,因此不要将具有副作用的代码放在断言中。

【讨论】:

【参考方案3】:

断言用于验证设计假设,通常根据输入参数和返回结果。例如

// Given customer and product details for a sale, generate an invoice

Invoice ProcessOrder(Customer Cust,Product Prod)

  assert(IsValid(Cust));
  assert(IsValid(Prod);
'
'
'
  assert(IsValid(RetInvoice))
   return(RetInvoice);


运行代码不需要断言语句,但它们会检查输入和输出的有效性。如果输入无效,则调用函数中存在错误。如果输入有效而输出无效,则此代码存在错误。有关断言使用的更多详细信息,请参阅design by contract。

编辑:正如其他帖子中所指出的,assert 的默认实现不包含在发布运行时中。许多人(包括我自己)会使用的一种常见做法是将其替换为发布版本中包含的版本,但仅在诊断模式下调用。这可以通过完整的断言检查对发布版本进行适当的回归测试。我的版本如下;

extern  void _my_assert(void *, void *, unsigned);

#define myassert(exp)                               \
                                                   \
    if (InDiagnostics)                              \
        if ( !(exp) )                               \
            _my_assert(#exp, __FILE__, __LINE__);   \
                                                   \

此技术的运行时开销很小,但它可以更轻松地跟踪任何使其进入该领域的错误。

【讨论】:

【参考方案4】:

使用断言检查“不可能发生”的情况。

典型用法:检查函数顶部的无效/不可能参数。

很少见,但仍然有用:循环不变量和后置条件。

【讨论】:

【参考方案5】:

断言是允许您测试程序中可能存在的任何假设的语句。这对于记录程序逻辑(前置条件和后置条件)特别有用。失败的断言通常会引发运行时错误,并且表明您的程序存在严重问题 - 您的断言失败是因为您认为正确的事情不是。通常的原因是:你的函数逻辑有缺陷,或者你的函数的调用者给你传递了错误的数据。

【讨论】:

【参考方案6】:

断言是您添加到程序中的东西,如果满足条件,它会导致程序立即停止,并显示错误消息。您通常将它们用于您认为在您的代码中永远不会发生的事情。

【讨论】:

【参考方案7】:

这并没有解决从早期 C 时代就传给我们的 assert 功能,但是如果您的项目可以使用 Boost,您还应该注意 Boost StaticAssert 功能.

标准 C/C++ 断言在运行时有效。 Boost StaticAssert 工具使您能够在编译时创建某些类的断言,甚至更早地捕获逻辑错误等。

【讨论】:

【参考方案8】:

这是一个断言是什么的definition,here 是一些示例代码。简而言之,断言是开发人员在任何给定点测试他(或她)关于代码状态的假设的一种方式。例如,如果您正在执行以下代码:

mypointer->myfunct();

您可能想要断言 mypointer 不为 NULL,因为这是您的假设—— mypointer 在调用之前永远不会为 NULL。

【讨论】:

以上是关于什么是断言?你为什么要使用它们?的主要内容,如果未能解决你的问题,请参考以下文章

assert用法

selenium知识思维导图|从元素定位到操作断言,助你快速入门自动化测试

什么时候用异常,什么时候用断言?

C语言调试利器——断言

对chai断言的学习总结

什么时候用异常,什么时候用断言?