4

我不明白 的目的assert()

我的讲师说 assert 的目的是发现错误。

例如 :

double divide(int a , int b ) 
{
  assert (0 != b);
  return a/b;
}

上述断言是否合理?我认为答案是肯定的,因为如果我的程序不应该使用0(数字零),但不知何故零确实找到了进入b变量的方式,那么代码有问题。

我对么 ?

你能告诉我一些合理的assert() 的例子吗?

问候

4

6 回答 6

16

assert如果程序正确,则用于验证应始终为真的事物。在您的示例中是否assert合理取决于以下规范divide:如果b != 0是前提条件,那么assert通常是验证它的首选方式:如果有人在不满足前提条件的情况下调用该函数,则这是一个编程错误,您应该终止程序带着极端的偏见,尽可能少做额外的工作。(通常情况下。有些应用程序不是这种情况,最好抛出异常,然后跌跌撞撞,希望最好。)但是,如果规范divide定义了 somw 行为时b == 0(例如,返回 +/- Inf),那么你应该实现这个而不是使用断言。

此外,assert如果事实证明它需要太多运行时间,则可以将其关闭。然而,一般来说,这应该只在代码的关键部分进行,并且只有在分析器显示您确实需要它时。

FWIW:与您的问题无关,但您发布的代码将返回0.0. divide( 1, 3 )不知何故,我不认为这是你想要的。

于 2012-08-28T15:04:24.993 回答
8

断言的另一个方面:
它们也是一种文档。

而不是像这样的评论

// ptr is never NULL
// vec has now n elements

写得更好

assert(ptr!=0);
assert(vec.size()==n);

评论可能会随着时间的推移而过时,并会引起混乱。但断言始终得到验证。
评论可以忽略。断言不能。

于 2012-08-28T15:55:05.940 回答
6

assert除了您通常在调试阶段使用的事实之外,您对 的评估非常准确assert...这是因为您不希望assert在生产代码期间触发...处理它们)是生产级代码中运行时错误管理的正确方法。

但一般来说,assert用于测试假设。如果在调试阶段代码中没有满足假设条件,特别是当您获得超出所需输入的值时,您希望程序在遇到错误时退出,以便您可以修复它。例如,假设您正在调用一个返回指针的函数,并且该函数永远不应返回NULL指针值。换句话说,返回NULL值不仅是错误条件的某种指示,而且意味着您对代码工作方式的假设是错误的。这是一个使用的好地方assert...您假设您的程序将以一种方式工作,如果不是,那么您不希望该错误传播到其他地方导致一些疯狂的难以找到的错误...您想在它发生时立即修复它发生。

最后,您可以将内置宏与assert诸如__LINE__和组合在一起,__FILE__这将为您提供发生断言的代码中的文件和行号,以帮助您快速识别问题区域。

于 2012-08-28T14:56:54.150 回答
3

断言的目的是在调试期间发出意外行为的信号(因为它仅在调试版本中可用)。您的示例是断言的合理案例。下一行可能会崩溃,但是使用断言,您可以选择在该行被命中之前中断执行,并进行一些调试。

这通常与异常并行完成 - 您断言表示有问题,并抛出异常以优雅地处理案例(甚至退出程序):

double divide(int a , int b ) 
{
  assert (0 != b);
  if ( b )
     return a/b;
  throw division_by_0_exception();
}

在某些情况下,您想继续执行,但仍想发出出现问题的信号。

于 2012-08-28T14:56:20.647 回答
1

Assert 用于在调试环境中测试有关您的代码的假设。断言通常对您的最终构建没有影响。

它是否是一个有效的测试完全是另一回事。如果不深入了解您的应用程序,我们将无法回答这个问题。

断言不应该失败。如果您看到断言可能失败的任何可能性,那么您需要一个 if 语句来处理那些条件不正确的情况。断言仅适用于您认为永远不会失败的条件。

于 2012-08-28T14:57:48.357 回答
1

断言用于在代码执行期间检查不变量,这些条件是程序员假设始终保持不变的条件,如果它们与假设不同,则代码中存在错误。

断言也可用于检查前置条件和后置条件,第一个在某些代码块之前检查并验证提供的数据/状态是否正确,第二个检查某些计算的结果是否正确。这有助于缩小问题/错误所在的位置:

assert( /*preconditions*/ );
/*here some algorithm - and maybe more asserts checking invariants*/
assert( /*postconditions*/ );

一些合理断言的例子:

  1. 检查函数返回值,例如,如果您调用一些外部 API 函数并且您知道它仅在编程错误的情况下返回一些错误值:

WinAPI Thread32First 函数要求提供的 LPTHREADENTRY32 结构已正确分配 dwSize 字段,以防出错。这个失败应该被断言捕获。

  1. 如果函数接受指向某些数据的指针,则在函数开头添加断言以验证它是否为非空。如果这个函数不能在空指针上工作,这是有道理的。

  2. 如果您在设置超时的情况下锁定了互斥锁,那么如果此超时结束,那么您可以使用断言来指示可能的竞争条件/死锁

......还有更多

断言的好技巧是在里面添加一些信息,例如:

assert(false && "此断言的原因");

“此断言的原因”将在消息框中显示给您

您可能还想知道我们也有静态断言来指示编译期间的错误。

于 2012-08-28T15:17:55.163 回答