Can #undef affect member functions in C++? - c++

I have an Unreal Engine 4 project with several plugins. On of these plugins contains a FileHelper class with a method CreateFile. This has worked fine for months, but in a recent commit, a different plugin added a call to FileHelper::CreateFile and now sometimes I get a linker error saying that CreateFileW is not a member of FileHelper (this doesn't appear in every build, which I cannot yet explain).
I went on to undefine CreateFile temporarily like this
#include "UtilPlugin/File/FileSystemHelper.h"
#ifdef _WIN32
#pragma push_macro("CreateFile")
#undef CreateFile
#endif //_WIN32
...//new code including CreateFile call
#ifdef _WIN32
#pragma pop_macro("CreateFile")
#endif //_WIN32
but now I get errors
C2039 'CreateFile': is not a member of 'FileSystemHelper'
C3861 'CreateFile': identifier not found
Since I know CreateFile is successfully called in other places (at least within the same plugin as the FileSystemHelper), I know that it exists.
Thus my question is, if the undefine can affect member functions like this.
I have moved the #undef part above the includes in code and I don't get an error anymore, but since it occurred seemingly randomly, I'm not entirely sure that I really fixed the problem.

Following shows a problematic case:
#define CreateFile CreateFileW
struct S
{
void CreateFile(); // Actually void CreateFileW();
};
And then
#undef CreateFile
void foo()
{
S s;
s.CreateFile(); // Error, "expect" s.CreateFileW()
}
As #define might modify meaning of code (locally), #undef "cancels" that modification locally too.

Related

#ifdef [true condition] #endif block. Commenting out #ifdef & #endif lines changes compile?

I have two header files. One calls the other after #define-ing a symbol used in the other one with #ifdef [symbol]... lotsa code #endif.
In VS2017, the code between the #ifdef & #endif shows as 'active' (not greyed out), so it thinks [symbol] is true and includes the code in the active code set.
However, If I comment out the #ifdef [symbol] and #endif lines, the result of the compile changes drastically - how can this be? I thought the #ifdef & #endif macros were pre-processor directives and don't exist at all for purposes of compiling the code. If #ifdef [symbol] evaluates as true, I thought they just disappeared. What am I missing?
First header file:
#ifndef _MPU6050_6AXIS_MOTIONAPPS20_H_
#define _MPU6050_6AXIS_MOTIONAPPS20_H_
#include "I2Cdev.h"
#include "helper_3dmath.h"
// MotionApps 2.0 DMP implementation, built using the MPU-6050EVB evaluation board
#define MPU6050_INCLUDE_DMP_MOTIONAPPS20
#include "MPU6050.h"
In the second header file (MPU6050.H), there is a long class definition for 'Class MPU6050' and this definition has a block guarded by
#ifdef MPU6050_INCLUDE_DMP_MOTIONAPPS20
....
....
....
#endif
This (I believe) is the source of some 'one definition rule' violations I've been trying to track down, so as an experiment I commented out the #define & #endif lines, thinking now there would be only one possible definition for 'Class MPU6050' and life would be good. What actually happened is the compiler blew a whole lot of 'undefined symbol' errors, as if the 'MPU6050_INCLUDE_DMP_MOTIONAPPS20' symbol hadn't been defined after all and the guard lines were preventing the guarded code from being compiled, even though VS2017's Intellisense shows it 'active'.
Since the symbol 'MPU6050_INCLUDE_DMP_MOTIONAPPS20' is defined, the guarded code in MPU6050.H should be compiled whether or not the #ifdef & #endif lines are actually there, right??
What am I missing?
The actual files are MPU6050_6Axis_MotionApps20.h and MPU6050.H from the Arduino\MP6050 folder at Jeff Rowberg's i2cDev GitHub account
TIA,
Frank
02/06/19 Addition: As a test, I placed a 'known-bad' line in the #ifdef/#endif guarded block, and the compiler flagged the line as an error. I believe this proves that the guarded block is indeed 'active' from the point of view of the compiler.
In addition, I commented out the line in MPU6050_6Axis_MotionApps20.h that #defined the 'MPU6050_INCLUDE_DMP_MOTIONAPPS20' symbol. Now the editor shows the guarded code as 'inactive' (grayed out), and the compiler acts consistently with that (complains that is is missing the function declarations from the guarded code section).
So, I have what appears to be a paradox; The compiler believes that the guarded code is active, but believes it disappears when I comment out the #ifdef & #endif lines, which should have been removed by the pre-processor ever saw the guarded code.
Any ideas?

Visual studio adding capital A to function name in error message

I've tried making a minimal testcase to reproduce it, but haven't been able to.
Adding a screenshot to show the error
this is the call to the SetClass function
m_luaState["MyClass"].SetClass<MyClass, I32>("AddTo", &MyClass::Add);
This is the MyClass:
class MyClass
{
public:
MyClass(I32 i) : m_i(i), m_j(2*i)
{
}
I32 m_j;
void Add(I32 iv)
{
std::cout << iv + m_i + m_j;
}
private:
I32 m_i;
};
Your RegisterClass(...) method name is being replaced by a Windows #define RegisterClass. Since you are compiling as ANSI, you are picking up the ANSI alias for RegisterClass which is RegisterClassA (it would be RegisterClassW if you were compiling Unicode).
You could either rename your RegisterClass(...) method if that's a viable option, exclude the conflicting Windows header (probably not an option), or conditionally #undef RegisterClass at the top of your header which declares your RegisterClass(...) method, something like:
#ifdef RegisterClass
#undef RegisterClass
#endif
Some additional reference about the conflicting symbol: RegisterClass function
This problem is actually quite interesting, and is nothing you have done wrong. It's because the RegisterClass Windows function and how Windows handle Unicode when programming.
Windows have two variants for almost all its function, if you see the table at the bottom of the linked MSDN reference you will see them mentioned as RegisterClassW and RegisterClassA. The W function is used for Unicode builds, where all strings and characters are of type wchar_t. The A variant is the "ANSI" variant, using normal char characters.
The problem here is that Windows uses macros to decide which of the funcitons to use, basically it does this
#ifdef UNICODE
# define RegisterClass RegisterClassW
#else
# define RegisterClass RegisterClassA
#endif
This is problematic because the preprocessor will replace your call to the RegisterClass member function with the RegisterClassA symbol, leading to your error.
The simple solution is to #undef the RegisterClass macro directly after including <windows.h> (or in some other suitable place). Another is to rename RegisterClass to something which doesn't clash with the Windows function.

Including DShow.h breaks VCL AnsiString::sprintf() on BDS2006

I finally got some time to upgrade my video capture class. I wanted to compare VFW (what I have used until now) and DirectShow. As expected, DirectShow is faster, but when I added info texts, suddenly AnsiString::sprint() is no longer a member of AnsiString.
After some struggle, I found a workaround as AnsiString::printf() still works, but I am curious how to fix this. Maybe some define from dshow.h and dstring.h are conflicting?
I cut down all the unnecessary code to show this problem:
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#include <dshow.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
static int i=0;
Caption=AnsiString().sprintf("%i",i); // this does not work
AnsiString s; s.printf("%i",i); Caption=s; // this does work
i++;
}
//---------------------------------------------------------------------------
It is just a simple VCL Form app with a single TTimer on it. The TTimer is incrementing the counter i and outputting it in the Form's Caption. The DirectX libs are not even linked, just headers included!
The Linker outputs error:
[C++ Error] Unit1.cpp(20): E2316 'sprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA' is not a member of 'AnsiString'
If I swap the vcl.h and dshow.hincludes, the compiler stops indstring.h` on this line:
AnsiString& __cdecl sprintf(const char* format, ...); // Returns *this
With this error message:
[C++ Error] dstring.h(59): E2040 Declaration terminated incorrectly
So, there is clearly some conflict (the AnsiString keyword is the problem). Putting dshow.h into a namespace does not help, either.
Does anyone have any clues?
Q1. How to fix this?
Q2. What/where exactly is causing this?
The only solution that I can think of, and should work (but I want to avoid it if I can), is to create an OBJ (or DLL) with the DirectShow stuff, and then link that into a standard VCL project without including dshow.h in it, and of course the exports must be without any funny stuff, too.
The problem is not with dshow.h itself, but is actually with strsafe.h instead, which dshow.h includes by default.
strsafe.h contains the following code 1:
#ifndef STRSAFE_NO_DEPRECATE
// Deprecate all of the unsafe functions to generate compiletime errors. If you do not want
// this then you can #define STRSAFE_NO_DEPRECATE before including this file
#ifdef DEPRECATE_SUPPORTED
...
#pragma deprecated(sprintf)
...
#else // DEPRECATE_SUPPORTED
...
#undef sprintf
#define sprintf sprintf_instead_use_StringCchPrintfA_or_StringCbPrintfA;
...
#endif // DEPRECATE_SUPPORTED
#endif // !STRSAFE_NO_DEPRECATE
1 There are similar #pragma and #define statements for many other deprecated "unsafe" C functions.
If both STRSAFE_NO_DEPRECATE and DEPRECATE_SUPPORTED are not defined (which is the case in this situation), the use of #define sprintf causes all subsequent references to any kind of sprintf symbol to be seen as sprintf_instead_use_StringCchPrintfA_or_StringCbPrintfA; during compiling.
That is why you are getting the compiler error. When vcl.h is included before strsafe.h, dstring.h gets included first, so the compiler sees the correct declaration for the AnsiString::sprintf() method, and then strsafe.h gets included (presumably by Unit1.h) before the compiler sees your Timer1Timer() code, so your calls to AnsiString().sprint("%i",i) are actually trying to call AnsiString().sprintf_instead_use_StringCchPrintfA_or_StringCbPrintfA;("%i",i), which fail.
When you swap the vcl.h and dshow.h includes, the #define sprintf statement in strsafe.h gets processed before dstring.h is included, so the compiler sees the following declaration for the AnsiString::sprintf() method in dstring.h and fails:
AnsiString& __cdecl sprintf_instead_use_StringCchPrintfA_or_StringCbPrintfA;(const char* format, ...); // Returns *this
To prevent this behavior, you could use an #undef sprintf statement after #include <dshow.h>, like JeffRSon suggested. However the correct solution is to define STRSAFE_NO_DEPRECATE before #include <strsafe.h>. You can do that by either:
adding #define STRSAFE_NO_DEPRECATE to your code before the #include <dshow.h> statement
adding STRSAFE_NO_DEPRECATE to the Conditionals list in your Project Options.
This solution is described on MSDN:
About Strsafe.h
When you include Strsafe.h in your file, the older functions replaced by the Strsafe.h functions will be deprecated. Attempts to use these older functions will result in a compiler error telling you to use the newer functions. If you want to override this behavior, include the following statement before including Strsafe.h.
#define STRSAFE_NO_DEPRECATE
To allow only character count functions, include the following statement before including Strsafe.h.
#define STRSAFE_NO_CB_FUNCTIONS
To allow only byte count functions, include the following statement before including Strsafe.h.
#define STRSAFE_NO_CCH_FUNCTIONS
Another supported solution is to define NO_DSHOW_STRSAFE before #include <dshow.h> so that it will not include strsafe.h anymore, thanks to this code in dshow.h:
#ifndef NO_DSHOW_STRSAFE
#define NO_SHLWAPI_STRFCNS
#include <strsafe.h>
#endif
I don't have this very version of dshow.h and dstring.h, so I cannot check it myself, but from the error messages you cite it seems that somewhere in dshow.h or its dependencies they declare an "sprintf" macro. You may look if you can find it.
In order to prevent that behaviour you need to delete this macro. Use
#undef sprintf
after the line that includes dshow.h.

How do I avoid name collision with macros defined in Windows header files?

I have some C++ code that includes a method called CreateDirectory(). Previously the code only used STL and Boost, but I recently had to include <windows.h> so I could look-up CSIDL_LOCAL_APPDATA.
Now, this code:
filesystem.CreateDirectory(p->Pathname()); // Actually create it...
No longer compiles:
error C2039: 'CreateDirectoryA' : is not a member of ...
Which corresponds to this macro in winbase.h:
#ifdef UNICODE
#define CreateDirectory CreateDirectoryW
#else
#define CreateDirectory CreateDirectoryA
#endif // !UNICODE
The pre-processor is redefining my method call. Is there any possible way to avoid this naming collision? Or do I have to rename my CreateDirectory() method?
You will be better off if you just rename your CreateDirectory method. If you need to use windows APIs, fighting with Windows.h is a losing battle.
Incidently, if you were consistent in including windows.h, this will still be compiling. (although you might have problems in other places).
You could create a module whose sole purpose is to #include <windows.h> and look up CSIDL_LOCAL_APPDATA wrapped in a function.
int get_CSIDL_LOCAL_APPDATA(void)
{
return CSIDL_LOCAL_APPDATA;
}
btw, Well done for working out what happened!
#undef CreateDirectory
As a developer working on a cross platform codebase, this is a problem. The only way to deal with it is to
ensure that windows.h is - on Windows builds at least - universally included. Then the CreateDirectory macro is defined in every one of your compilation units and is universally substituted with CreateDirectoryW. Precompiled headers are ideal for this
OR, if that is an unpleasant proposition, (and it is for me)
isolate windows.h usage into windows specific utility files. Create files that export the basic required functionality. The header files must use data types that are compatible with, but do NOT depend on the inclusion of windows.h. The cpp implementation file must (obviously) use windows.h.
If your utlility functions need to include project header files with conflicting symbols then the following pattern is a necessity:
#include <windows.h>
#ifdef CreateDirectory
#undef CreateDirectory
#endif
// etc
#include "some_class_with_CreateDirectory_method.h"
// ...
You will need to then explicitly call the non macro version of any windows api functions you have #undef'd - CreateDirectoryA or W etc.
push macro, undef it and pop the macro again:
#pragma push_macro("CreateDirectory")
#undef CreateDirectory
void MyClass::CreateDirectory()
{
// ...
}
#pragma pop_macro("CreateDirectory")
You can take a back up of CreateDirectory, then undefine it, and then define it again when you finish your job with you custom one.
#ifdef CreateDirectory
#define CreateDirectory_Backup CreateDirectory
#undef CreateDirectory
#endif
// ...
// Define and use your own CreateDirectory() here.
// ...
#ifdef CreateDirectory_Backup
#define CreateDirectory CreateDirectory_Backup
#undef CreateDirectory_Backup
#endif
Note that name conflict usually comes from a certain header file being included. Until then stuff like CreateDirectory and GetMessage isn't pulled into visibility and code compiles without a problem.
You can isolate such an inclusion into a wrapper header file and "#undef whatever" at its end. Then, whatever name collision you have will be gone. Unless, of course, you need to use those macros in your own code (yeah, so very likely...)
#pragma push_macro("CreateDirectory")
If nothing works, instead of renaming you could use your own namespace for your functions.

Per-file enabling of scope guards

Here's a little problem I've been thinking about for a while now that I have not found a solution for yet.
So, to start with, I have this function guard that I use for debugging purpose:
class FuncGuard
{
public:
FuncGuard(const TCHAR* funcsig, const TCHAR* funcname, const TCHAR* file, int line);
~FuncGuard();
// ...
};
#ifdef _DEBUG
#define func_guard() FuncGuard __func_guard__( TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), __LINE__)
#else
#define func_guard() void(0)
#endif
The guard is intended to help trace the path the code takes at runtime by printing some information to the debug console. It is intended to be used such as:
void TestGuardFuncWithCommentOne()
{
func_guard();
}
void TestGuardFuncWithCommentTwo()
{
func_guard();
// ...
TestGuardFuncWithCommentOne();
}
And it gives this as a result:
..\tests\testDebug.cpp(121):
Entering[ void __cdecl TestGuardFuncWithCommentTwo(void) ]
..\tests\testDebug.cpp(114):
Entering[ void __cdecl TestGuardFuncWithCommentOne(void) ]
Leaving[ TestGuardFuncWithCommentOne ]
Leaving[ TestGuardFuncWithCommentTwo ]
Now, one thing that I quickly realized is that it's a pain to add and remove the guards from the function calls. It's also unthinkable to leave them there permanently as they are because it drains CPU cycles for no good reasons and it can quickly bring the app to a crawl. Also, even if there were no impacts on the performances of the app in debug, there would soon be a flood of information in the debug console that would render the use of this debug tool useless.
So, I thought it could be a good idea to enable and disable them on a per-file basis.
The idea would be to have all the function guards disabled by default, but they could be enabled automagically in a whole file simply by adding a line such as
EnableFuncGuards();
at the top of the file.
I've thought about many a solutions for this. I won't go into details here since my question is already long enough, but let just say that I've tried more than a few trick involving macros that all failed, and one involving explicit implementation of templates but so far, none of them can get me the actual result I'm looking for.
Another restricting factor to note: The header in which the function guard mechanism is currently implemented is included through a precompiled header. I know it complicates things, but if someone could come up with a solution that could work in this situation, that would be awesome. If not, well, I certainly can extract that header fro the precompiled header.
Thanks a bunch in advance!
Add a bool to FuncGuard that controls whether it should display anything.
#ifdef NDEBUG
#define SCOPE_TRACE(CAT)
#else
extern bool const func_guard_alloc;
extern bool const func_guard_other;
#define SCOPE_TRACE(CAT) \
NppDebug::FuncGuard npp_func_guard_##__LINE__( \
TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), \
__LINE__, func_guard_##CAT)
#endif
Implementation file:
void example_alloc() {
SCOPE_TRACE(alloc);
}
void other_example() {
SCOPE_TRACE(other);
}
This:
uses specific categories (including one per file if you like)
allows multiple uses in one function, one per category or logical scope (by including the line number in the variable name)
compiles away to nothing in NDEBUG builds (NDEBUG is the standard I'm-not-debugging macro)
You will need a single project-wide file containing definitions of your category bools, changing this 'settings' file does not require recompiling any of the rest of your program (just linking), so you can get back to work. (Which means it will also work just fine with precompiled headers.)
Further improvement involves telling the FuncGuard about the category, so it can even log to multiple locations. Have fun!
You could do something similar to the assert() macro where having some macro defined or not changes the definition of assert() (NDEBUG in assert()'s case).
Something like the following (untested):
#undef func_guard
#ifdef USE_FUNC_GUARD
#define func_guard() NppDebug::FuncGuard __npp_func_guard__( TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), __LINE__)
#else
#define func_guard() void(0)
#endif
One thing to remember is that the include file that does this can't have include guard macros (at least not around this part).
Then you can use it like so to get tracing controlled even within a compilation unit:
#define USE_FUNC_GUARD
#include "funcguard.h"
// stuff you want traced
#undef USE_FUNC_GUARD
#include "funcguard.h"
// and stuff you don't want traced
Of course this doesn't play 100% well with pre-compiled headers, but I think that subsequent includes of the header after the pre-compiled stuff will still work correctly. Even so, this is probably the kind of thing that shouldn't be in a pre-compiled header set.