在C和C ++中assert
是非常重量级例程,向stdout
写入错误并终止程序。在我们的应用程序中,我们为assert实现了一个更强大的替换,并给它自己的宏。我们已尽一切努力用我们的宏替换assert
,但仍有许多方法assert
可以重新引入(例如,来自内部第三方库,天真注入等)
有关如何减少,限制甚至根除assert
用途的任何建议?最好的答案是编译器可以为我们捕获的答案,因此我们不必像现在一样照看代码库。
答案 0 :(得分:14)
实际上,我不确定我是否真的理解这个问题。如果断言,断言只会很昂贵,无论如何这都很好,因为你现在处于异常状态。
assert
仅在调试版本中启用,因此请使用第三方库的版本构建。但实际上,断言不应该每时每刻都在消失。
答案 1 :(得分:2)
这取决于(至少部分)你正在改变的东西。假设你不介意它打印出它的正常消息,并且主要想要去掉它abort()
,你可以考虑单独留下assert()
,而是定义你自己的{{1}版本}}
从理论上讲,这样做是不可移植的 - 但实际上,abort()
在标准库中是一个相当普通的函数,如果你链接自己的函数,你会得到它的行为。有时(特别是一些微软链接器)你必须做一些工作才能让链接器合作用你的abort()
替换它们,但它很少很难。
答案 2 :(得分:2)
改进内置断言工具(提供堆栈跟踪,核心转储,谁知道)可以很方便。在这种情况下,如果您在让开发人员遵循您所拥有的任何标准(例如“而不是assert()
使用SUPER_ASSERT()
”或其他任何标准)时遇到问题,您可以自己设置{{1}头文件在编译器的头文件的运行时目录之前的include路径中。
这几乎可以保证使用标准assert.h
宏的任何人都会收到编译器错误或获得断言功能(取决于你的assert()
标题的内容)。
答案 3 :(得分:2)
我认为你的问题完全有效。如果您已实现自己的错误处理,则可能需要:
话虽如此,我认为任何解决办法都不会有效。
如果幸运的话,第三方库使用ASSERT宏,只要定义此宏的文件对多个文件有#pragma once
或#ifndef __HEADERFILE_H__ #define __HEADERFILE_H__
条款,您就可以重新定义自己包容性。单独包含头文件,重新定义ASSERT,你很好。
如果它们直接包含assert.h或cassert,你只能修补我猜的代码。进行最少的代码更改,将更改保存为修补程序文件,并在更新库时希望修补程序仍然有效。将修补程序添加到版本控制。
如果这不起作用,请重新考虑问题,如果您确实需要第三方库中的内部断言。仅发布发布版本,这将摆脱断言,并添加ASSERT以检查代码中的正确性。检查返回值的有效性。如果触发了这样的ASSERT,您仍然可以深入了解第三方代码以查看导致问题的原因。
答案 4 :(得分:2)
我认为这个问题是有效的。
如果触发了我自己的断言扩展为asm(“int3”),这相当于一个断点。我还发现调试比简单终止更有用。
我简单地称它为“ASSERT()”而不是正常的“assert()”,并且完全避免使用assert()。
答案 5 :(得分:1)
最明显的方法似乎是给自己的断言版本自己的名字,与assert()
略有不同。然后你可以搜索文本,查看链接器消息等文字字符串“_assert”,你知道你看到它时会遇到问题。
在我自己的代码中,我总是使用Assert()
,它扩展为我自己的执行断言的函数,或者扩展为((void)0)
以用于发布版本。编译器会将((void)0)
表达式转换为空,但它仍然算作表达式。因此
Assert(3 == x);
将变成
((void)0);
分号有一个地方可以去。
顺便说一下,我曾经在一个GUI应用程序上工作,其中assert是一个特殊的GUI模式弹出对话框。你有三个选择:忽略,永远忽略或者休息。忽略会忽略断言并继续运行。永远忽略会设置一个标志,直到你在调试器中重新启动程序,该断言将不再触发。中断将允许断言进入调试器。
我不记得他们如何保证每个断言都有自己的标志。也许当你编写Assert()调用时,你必须指定一个唯一的整数?如果它比那更自动,那将是很好的。我很确定实际的implmentation是一个有点向量,当你永远选择忽略时它会设置一点。
答案 6 :(得分:1)
assert()
通常#define
为((void)0) for release code(#define NDEBUG
),因此根本没有开销。
使用测试版时,性能开销是否会影响测试的真实性?
答案 7 :(得分:1)
如果源代码在您的控制之下:
#define NDEBUG
// Before
#include <assert.h>
// Or other header that includes assert.h
或使用预编译的头或编译选项来定义NDEBUG
。
对于第三方二进制文件,请使用它们的发行版本。
答案 8 :(得分:1)
您似乎错过了第三方代码最有可能在“标准”assert
行为假设下编写的事实。即代码期望程序在失败的断言时终止。如果断言条件被破坏,则断言后面的代码通常不会也将无法正常工作。在100个中的99个案例中根本不起作用。在100个中的99个案例中,它将简单地崩溃,即程序将终止。
要相信通过覆盖第三方代码中的assert
行为,您将以某种方式延长程序的使用时间是最好的。
答案 9 :(得分:0)
在库标题中查找assert
(假设它们是您文件系统上的真实文件)并将其替换为无效的文件
// #define assert(condition) ... /* old definition */
#define assert(condition) ((condition) & "PLEASE DO NOT USE ASSERT" = 42)