在C++中实现断言检查的最佳方法是什么



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

MFC非常简单,我只是使用ASSERT(某物)。

非MFC方式是什么?

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

编辑:<assert.h><cassert>有什么区别?

接受

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

#include <cassert>
assert(something);

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

#include <boost/static_assert.hpp>
BOOST_STATIC_ASSERT(sizeof(int) == 4);  // compile fails if ints aren't 32-bit
这取决于

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

有几种类型的断言:

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

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

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

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

我希望这有帮助!

言(通常)仅调试

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

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

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

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

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

断言只会在调试版本上检测和处理错误。

因此,我们添加了XXX_ASSERT宏以及XXX_RAISE_ERROR宏。

XXX_ASSERT宏将执行与 ASSERT 宏相同的操作,但它将在调试和发布中构建。它的行为(编写日志、打开消息框、不执行任何操作等)可以通过 .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),但在其他任何地方,它都很好。事实上,人们可以使用任何首选的错误处理,并且可以在开发人员计算机上,测试人员甚至用户上随意激活它,这是非常有用的。

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

是 C 标头

是C++标准库标头...它通常包括<断言.h>

基本断言用法

#include <cassert>
/* Some code later */
assert( true );

最佳实践说明

断言用于标识应为 true 的运行时状态。 因此,它们在发布模式下编译出来。

如果你有一个情况,你希望断言总是命中,你可以将 false 传递给它。 例如:

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

也可以通过断言传递消息:

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

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

  • 切换断言基于每个模块进行本地化测试。
  • 创建在大多数调试版本中编译的附加断言宏。 这对于调用频率非常高(每秒数百万次)且不太可能不正确的代码是可取的。
  • 允许用户禁用当前命中断言、编译单元中的所有断言或代码库中的所有断言。 这将阻止良性断言被触发,从而创建不可用的生成。

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

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

或:

#define MYASSERT(EXPR) if (!(EXPR)) __debugbreak();
特定于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());

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

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

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

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

这在呼叫者网站上为我中断...

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

这是我

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

这是一个插入式 2 个文件库,您可以轻松添加到您的项目中。

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

相关内容

  • 没有找到相关文章

最新更新