Someone may wonder what the difference is between Debug and Release mode, and whether it is possible to mix them.
syperk said: “As a result, I’ve switched to compiling my debug builds using the /MD switch. If you do this, you also have to undefine the _DEBUG preprocessor macro. Otherwise you get lots of errors about _CrtDebugReportW() not found. This function is apparently inserted into your code if _DEBUG is defined, but is only defined in the debug CRT. As long as optimization is off it seems to be perfectly possible to debug programs compiled this way, and there are no concerns about CRT incompatibility.”.
But that is not true. There are many problems. In my opion, the most important one is that it is not a good idea to link different modules compiled with different compiler options in C++, especially when conditional compilation is involved.
In fact, “Debug” & “Release” are only two sets of predefined compiler flags and macros definitions provided by the IDE (_DEBUG and NDEBUG are two representing macros). The compiler doesn’t aware of that (but it has some magic behind compile option “MD” and “MDd”).
The main problem is that program compiled using “Debug” setting and the release runtime don’t share the same compiler flags, and they are highly possible to be incompatible.
For example, if you change “MDd” -> “MD” in your debug configuration, and compile the following code (don’t remove the _DEBUG macro, otherwise the “Debug” version is no longer a debug version (/MDd will define this macro implicitly, and IDE will explicitly define it via compiler flag)) :
using namespace std;
You’ll find that the program function properly. If you check the generated exe, you’ll find that it refer to two dlls, one is msvcp90d.dll, the other is msvcr90.dll. Oops! You’re mixing the debug and release runtime libraries! And that hide the potential incompatibility!
The magic is here (in use_ansi.h):
#else /* _DEBUG */
#endif /* _DEBUG */
If you disable this trick, and link to msvcp90.dll, you’ll get unresolved symbol error, that is because the implementation of string class is different in “Debug” and “Release” mode. This is one example of the incompatibility.
error LNK2019: unresolved external symbol “__declspec(dllimport) public: __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(struct std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::_Has_debug_it)” (__imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@U_Has_debug_it@01@@Z) referenced in function _main
It’s fortunate that this is a linker error. Otherwise, you’ll waste lots of time in debugging to find out the subtle incompatibility.
STL in VC9 devotes lots of efforts to prevent break like this, then you can disable macros like “_HAS_ITERATOR_DEBUGGING” as you like, and keep your code compatible with the runtime (which is compiled with the macro enabled). But it only applies when you stick to debug or stick to release. It is really tricky to guarantee that, and I think you should never rely on this.