如何获得DebugBreak声明,而不包括Windows.h?

我们有一个C ++库。 我们正在提供一个自定义断言,放弃Posix NDEBUGassert (下面的故事)。

Windows下,断言如下所示:

 # define CRYPTOPP_ASSERT(exp) { \ if (!(exp)) { \ std::ostringstream oss; \ oss << "Assertion failed: " << (char*)(__FILE__) << "(" \ << (int)(__LINE__) << "): " << (char*)(__FUNCTION__) \ << std::endl; \ std::cerr << oss.str(); \ DebugBreak(); \ } \ } 

我们遇到的问题是,我们必须包含<windows.h> ,即使在定义了WIN32_LEAN_AND_MEAN ,也会带来很多额外的负担。 一些额外的cruft,如minmax ,打破了C ++编译。 事实上,testing我们的变化打破了我们。

我们通过查找<windows.h>寻找一个“只包含debugging”types的定义,但是我们找不到它。 我们也尝试添加extern void WINAPI DebugBreak(void); 根据微软在DebugBreak的文档 ,但由于重新定义的符号导致编译错误。

添加NO_MIN_MAX (我认为这是macros)不是一个选项,因为我们正在改变定义在用户程序中,当定义交叉授粉我们的标题和用户代码。 相关内容请参阅限制#include指令和朋友的范围 。

使用#pragma push_macro#pragma pop_macro不是一个选项,因为我们支持Microsoft编译器回到VC ++ 6.0。 最早的可用的编译是VS2003。

由于中断,我们希望包含<windows.h> 。 如何在不包含Windows.h的情况下获得DebugBreak的声明?

提前致谢。


这是一个减less的情况:

 // cl.exe /c assert.cpp #include <algorithm> // #include <windows.h> // #ifndef WINAPI // # define WINAPI __stdcall // #endif // extern void WINAPI DebugBreak(void); #define MY_ASSERT(exp) { \ if (!(exp)) { \ DebugBreak(); \ } \ } void dummy(int x1, int x2) { MY_ASSERT(x1 == std::min(x1, x2)); } 

用我们的extern声明模拟一个用户程序时出现错误。 此testing发生在安装了VS2012和VS2013的Windows 8.1 x64上。 我们还使用了开发人员命令提示符。

 Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86 Copyright (C) Microsoft Corporation. All rights reserved. assert.cpp assert.cpp(11) : warning C4273: 'DebugBreak' : inconsistent dll linkage C:\Program Files (x86)\Windows Kits\8.1\include\um\debugapi.h(70) : see previous definition of 'DebugBreak' assert.cpp(21) : error C2589: '(' : illegal token on right side of '::' assert.cpp(21) : error C2059: syntax error : '::' assert.cpp(21) : error C2143: syntax error : missing ';' before '{' 

当我们检查<debugapi.h>我们看到:

 WINBASEAPI VOID WINAPI DebugBreak( VOID ); 

WINBASEAPI扩展到额外的macros。 我不认为我们能够在所有的平台上把它们都弄好。


我们有一个跨平台的C ++安全库,它最近抓到了CVE-2016-7420 。 它被归类为信息披露由于潜在的数据丢失,如果声称被解雇。 当敏感数据发送到文件系统(核心转储和崩溃报告)时发生丢失; 并透露给第三方(苹果通过CrashReporter,Ubuntu通过Apport,微软通过Windows错误报告,开发人员等)。

断言从来没有在我们的生产/发布中被解雇,因为我们的Makefile和我们的Visual Studio解决scheme很好地configuration了这个库。 在生产/发布构build中,断言被删除,C ++ throw()处理错误条件。 断言存在于debugging/开发人员configuration中,因此代码将自行debugging,并使程序员免于任务。

在分析之后,我们意识到logging“发布/生成构build必须使用-DNDEBUG是一个不完整的修复 。 人们不会阅读文档; 如果RTFM工作,那么现在就会发生。 另外,CMake不会定义它,Autotools不会定义它,Eclipse不会定义它,等等。我们实际上和CVE之前一样。 我们所做的只是把责任推到一边而不减less风险。

Solutions Collecting From Web of "如何获得DebugBreak声明,而不包括Windows.h?"

你可以使用内在的,它的工作原理包括:

 __debugbreak(); 

只需添加一个新的源代码文件,其中除了:

 #include <windows.h> void MyDebugBreak(void) { DebugBreak(); } 

根据需要导出,并在您的宏中调用MyDebugBreak()而不是DebugBreak()。

您可以只在Windows版本中包含该文件,或者根据需要添加#if块。

声明DebugBreak似乎工作正常使用Visual Studio 6和2015提供你声明它__stdcallextern "C" 。 由于VC ++ 6在算法头文件中似乎没有包括std::min我已经修改了一下你的例子,但是如果第一个参数大于第二个参数,那么当使用cl -nologo -W3 -O2 -Zi -NDEBUG -o assert.exe assert.cpp -link -subsystem:console -debug建立断言时cl -nologo -W3 -O2 -Zi -NDEBUG -o assert.exe assert.cpp -link -subsystem:console -debug

 #include <stdlib.h> #include <stdio.h> #include <string.h> extern "C" extern void __stdcall DebugBreak(void ); #define MY_ASSERT(exp) { \ if (!(exp)) { \ DebugBreak(); \ } \ } void dummy(int x1, int x2) { MY_ASSERT(x1 < x2); } int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "usage: assert integer integer\n"); exit(1); } int a = strtol(argv[1], NULL, 0); int b = strtol(argv[2], NULL, 0); dummy(a, b); return 0; }