21

我的意思是,我需要做什么才能在我的代码中使用有用的断言?

MFC 很简单,我只使用 ASSERT(something)。

什么是非MFC方式?

编辑:是否可以停止断言在 assert.c 中的中断而不是我的名为 assert() 的文件?

编辑:<assert.h> &之间有什么区别<cassert>

接受的答案:这篇文章中有很多很好的答案,我希望我能接受多个答案(或者有人会将它们全部结合起来)。所以答案被授予费鲁乔(第一个答案)。

4

11 回答 11

29
#include <cassert>

assert(something);

对于编译时检查,Boost 的静态断言非常有用:

#include <boost/static_assert.hpp>

BOOST_STATIC_ASSERT(sizeof(int) == 4);  // compile fails if ints aren't 32-bit
于 2008-10-07T18:23:00.360 回答
13

这取决于您是否正在寻找在 Visual C++ 之外工作的东西。它还取决于您要查找的断言类型。

有几种类型的断言:

  1. 预处理器
    这些断言是使用预处理器指令完成的 预#error
    处理器断言只在预处理阶段进行评估,因此对模板等东西没有用处。

  2. 执行时间
    这些断言是使用执行时间中assert()定义的函数完成的,<cassert>
    断言仅在运行时进行评估。正如 BoltBait 指出的那样,如果NDEBUG宏已定义,则不会编译。

  3. 正如您所说,静态
    这些断言是通过使用ASSERT()宏完成的,但前提是您使用的是 MFC。我不知道另一种方法来执行作为 C/C++ 标准一部分的静态断言,但是,Boost 库提供了另一种解决方案:static_assert. Boost 库中
    的函数将被添加到C++0x 标准中。static_assert

作为附加警告,assert()Ferruccio 建议的函数与 MFCASSERT()宏的行为不同。前者是执行时断言,而后者是静态断言。

我希望这有帮助!

于 2008-10-07T19:03:27.520 回答
10

断言(通常)仅调试

“断言”的问题在于它通常在调试二进制文件中,并且一些开发人员使用它们,就好像代码仍在生产中一样。

这本身并不邪恶,因为代码应该经过密集测试,因此肯定会发现并删除产生断言的错误。

但有时(大多数时候?),测试并不像想要的那样密集。我不会谈论直到最后一刻我们必须编码的旧工作(不要问......有时,经理只是......嗯......)......断言你有什么意义添加到将在下一分钟编译并作为发布二进制文件交付给客户端的代码?

在(某些)现实生活应用程序中断言

在我们的团队中,我们需要一些东西来检测错误,同时需要其他东西来处理错误。我们可能在 Release Build 中需要它。

Assert 将仅在调试构建时检测和处理错误。

所以我们添加了一个 XXX_ASSERT 宏和一个 XXX_RAISE_ERROR 宏。

XXX_ASSERT 宏与 ASSERT 宏做同样的事情,但它会在 Debug 和 Release 中构建。它的行为(写日志、打开消息框、什么都不做等)可以由 .INI 文件控制,然后,它将中止/退出应用程序。

这被用作:

bool doSomething(MyObject * p)
{
   // If p is NULL, then the app will abort/exit
   XXX_ASSERT((p != NULL), "Hey ! p is NULL !") ;
   
   // etc.
}

XXX_RAISE_ERROR 宏只会“记录”错误,但不会尝试处理它。这意味着它可以将消息记录在文件中和/或打开带有消息的 MessageBox 和一个按钮继续,另一个按钮启动调试会话(根据 .INI 文件配置)。这被用作:

bool doSomething(MyObject * p)
{
   if(p == NULL)
   {
      // First, XXX_RAISE_ERROR will alert the user as configured in the INI file
      // perhaps even offering to open a debug session
      XXX_RAISE_ERROR("Hey ! p is NULL !") ;
      // here, you can handle the error as you wish
      // Than means allocating p, or throwing an exception, or
      // returning false, etc.
      // Whereas the XXX_ASSERT could simply crash.
   }
   
   // etc.
}

在我们的库中引入它们一年后,只使用了 XXX_RAISE_ERROR。当然,它不能用于应用程序的时间关键部分(我们有一个 XXX_RAISE_ERROR_DBG),但在其他任何地方,它都很好。并且可以使用任何首选的错误处理,并且可以在开发人员计算机、测试人员甚至用户上随意激活它,这一事实非常有用。

于 2008-10-07T21:22:27.893 回答
9

要在第二次“编辑”中回答问题:

<assert.h> 是 C 头文件

<cassert> 是 C++ 标准库头文件...它通常包括 <assert.h>

于 2008-10-07T18:42:07.797 回答
7

基本断言用法

#include <cassert>

/* Some code later */
assert( true );

最佳实践笔记

断言用于识别应该为 true 的运行时状态。结果,它们在发布模式下被编译出来。

如果您希望断言始终命中,则可以将 false 传递给它。例如:

switch ( someVal ):
{
case 0:
case 1:
  break;
default:
  assert( false ); /* should never happen */
}

也可以通过 assert 传递消息:

assert( !"This assert will always hit." );

成熟的代码库经常扩展断言功能。一些常见的扩展包括:

  • 在每个模块的基础上切换断言以本地化测试。
  • 创建在大多数调试版本中编译出来的附加断言宏。这对于被非常频繁地调用(每秒数百万次)并且不太可能不正确的代码是可取的。
  • 允许用户禁用当前命中的断言、编译单元中的所有断言或代码库中的所有断言。这会阻止良性断言被触发,从而创建不可用的构建。
于 2008-10-07T19:06:09.090 回答
6

要中断调用断言的文件,您可以使用引发异常或调用的自定义宏__debugbreak

#define MYASSERT(EXPR, MSG) if (!(EXPR)) throw MSG;

或者:

#define MYASSERT(EXPR) if (!(EXPR)) __debugbreak();
于 2008-10-07T18:36:34.437 回答
5

Microsoft 特定的 CRT 断言

#include <crtdbg.h>
#include <sstream>
...
// displays nondescript message box when x <= 42
_ASSERT(x > 42);
// displays message box with "x > 42" message when x <= 42
_ASSERTE(x > 42);
// displays message box with computed message "x is ...!" when x <= 42
_ASSERT_EXPR(
   x > 42, (std::stringstream() << L"x is " << x << L"!").str().c_str());
于 2008-10-07T19:56:39.020 回答
3

有一个更高级的开源库,称为 ModAssert,它具有适用于 Visual C++ 和 gcc 的断言。可能也在其他编译器上,不确定。学习它需要一些时间,但是如果您想要不依赖于 MFC 的良好断言,请查看这些。它位于http://sourceforge.net/projects/modassert/

于 2009-11-17T08:48:23.600 回答
1

使用智能感知在 Visual Studio 中打开它(右键单击)

// cassert standard header
#include <yvals.h>
#include <assert.h>

yvals.h 是 Windows 的东西。因此,就 assert() 本身而言,包含它的两种方式是相同的。使用它是一个好习惯,<cxxx>因为它通常不是那么简单(命名空间包装和其他魔法)

这对我来说在呼叫者网站上中断了......

这里有一篇文章解释了为什么你不想自己写这个宏。

于 2008-10-07T18:55:24.617 回答
1

这是我在 C++ 中对断言工具的最新迭代:http: //pempek.net/articles/2013/11/17/cross-platform-cpp-assertion-library/

这是一个包含 2 个文件的插件库,您可以轻松地将其添加到您的项目中。

于 2014-02-10T20:26:46.580 回答
1

回答提问者的第三个问题:我们使用“cassert”而不是“assert.h”的第一个原因是,在 C++ 的情况下,考虑到 C++ 编译器可能不会在代码中存储函数描述这一事实文件,但在 dll 或编译器本身中。第二个是可能会对函数进行细微的更改,以促进 C 和 C++ 之间的差异,无论是现在还是将来。因为 assert.h 是一个 C 库,所以在 C++ 中首选使用“cassert”。

于 2014-11-20T07:40:24.743 回答