0

在调试期间使用断言的示例:

char* append(char* pStr, const char* pAddStr)
{
    // Verify non-null pointers

    assert(pStr != nullptr);
    assert(pAddStr != nullptr);

    // Code to append pAddStr to pStr...
}

在一个简单的程序中调用带有空指针参数的 append() 函数在我的机器上产生了以下诊断消息:

Assertion failed: pStr != nullptr, file c:\beginning visual c++ 2010\examples visual studio project files\tryassertion\tryassertion\tryassertion.cpp, line 10

我想知道断言是否必要。如果我可以使用 if-else 表达式来输出我自己的错误消息,那么使用它们有什么意义?

4

3 回答 3

4

断言条件检查;它只是一个类似这样的宏(简化):

#define assert(b) if (!(b)) { std::cerr << ...; exit(1); }

我可以想到两个优点:

  1. 当您在发布模式下编译(即不是在调试模式下)时,所有的asserts 都将编译为空,因此您不会产生运行时开销。
  2. assert是成语;其他程序员知道要寻找它们,它们也与“正常”控制流不同。
于 2011-12-11T18:22:39.750 回答
1

断言用于确保满足某些基本假设。基本上,您在“不可能发生”的每种情况下都放入一个断言,最常见的断言是如何使用 API,例如前置条件和后置条件(如您的示例,其中包含检查附加函数的正确使用的断言)。对于其他已知在运行时发生且无法事先预防的错误(例如,找不到文件或权限不足的错误),您将不得不编写错误处理代码。

断言不包含在发布编译中,因此它们只能用于捕获在调试模式测试运行中已经发生的关键编程错误。

于 2011-12-11T18:26:00.453 回答
1

当唯一违反断言的情况是程序逻辑中的错误时,您应该使用断言。对于由于输入或外部可能条件(即文件丢失)而可能确实发生的事情,您使用正常的if-条件。thenelse

当您确定程序逻辑有问题时,尝试继续执行并没有多大意义……您的程序的工作方式与您的想法不同(因为否则不会触发断言),因此最好选择只是大喊问题所在并立即死亡。

当代码以“发布”模式编译时,断言通常会被删除,即使如果程序逻辑非常复杂并且如果继续执行产生错误输出会产生比停止执行更大的问题,将它们保留在适当的位置可能是有意义的。

请注意,有时新手程序员陷入断言的“陷阱”是,当断言代码被删除以用于发布模式时,断言内的表达式不再被评估,因此如果您的程序依赖于该表达式的副作用,那么您'会有麻烦的......例如:

...
assert(insert_record(db, data) == DB_OK);  // <== this is bad
...

当断言被定义掉时,插入根本不会发生,留下一个在发布模式下不起作用的程序,而当你尝试调试问题时它会起作用。

于 2011-12-11T18:37:28.630 回答