Jump to content
  • Advertisement
novus22

C++ ERROR enum in logger class conflicting w/ Windows.h macro

Recommended Posts

I have the following snippet of code in my logger header file: 

namespace X {
	
  enum class LogPriority {
		DEBUG = 1,
		INFO = 2,
		CONFIG = 3,
		WARNING = 4,
		ERROR = 5
	};

....

However, I also am including <Windows.h>. It defines the macro ERROR as "0", and therefore the ERROR priority evaluates to 0 = 5. I've searched it up and apparently I can use undef to undefine the macros from the windows header, but I'm not too familiar with the preprocessor so I'm not too sure if undefining ERROR will cause future problems. Is that a safe thing to do? or are there better ways of going on about this? I can indeed change the casing of the enum values, but I'd then be tempted to change all the other enum values in my project to have it standardized throughout, so currently that's a last resort for me. 

Thanks in advance

Share this post


Link to post
Share on other sites
Advertisement
Posted (edited)

I think if you use:

#define NOGDI

before including windows.h, then the ERROR macro won't be included. It might solve your problem more gracefully. I just figure because it is coming from wingdi.h and it is surrounded by a big #ifndef NOGDI . For example, you can also avoid including the min and max macros by defining NOMINMAX the same way.

Edited by turanszkij

Share this post


Link to post
Share on other sites

Thank you both. That's a good fix but I guess i'll stick with the general accepted standard of not having all uppercase for enum values and go through with the effort of renaming all of them. Just so I won't be having this problem in the future as well. 

Share this post


Link to post
Share on other sites

The C++ "coding standard" if there exists one; I doubt when looking at the projects on GitHub... , is something odd anyways. The stl writes anything lowercase and in my opinion this is something oldschool. I prefer the C# standard so anything except non-public variables and arguments is written in titlecase, while non-public variables and function arguments are written lowercase.

But anyways, depending how extensively you use the Windows.h header file, there are several ways to minify it. You can as @turanszkij mentioned define several flags to exclude functionality but what I found some time ago is the Unreal way. They define those API functions as extern "C" and just let the linker bind the coresponding function features from the Windows API. No defines, no pollution and it feels very clean but you are limited because the more you want to use, the more you need to define by yourself.

I use the linker minification in my game engine classes that abstract certain API like filesystem handling, threading and so on

Share this post


Link to post
Share on other sites
On 7/9/2019 at 4:32 AM, Shaarigan said:

The C++ "coding standard" if there exists one; I doubt when looking at the projects on GitHub.

C++ is based on the C language.  The C language was invented before the fascists learned how to harness coders so there is no centrally-dictated de jure way to do your job.  The convention of using all-uppercase macro names was introduced by Dennis Ritchie as he ported the Unix operating system in 1972 and it was first documented in "The C Programming Language" by Brian W. Kernighan and Dennis Ritchie in 1978.  Because this was most coder's introduction to the C language, and because Unix was how most people used the C language for decades, this coding convention became the de facto standard.  Bjarne Stroustrup continued with that convention when he published "The C++ Programming Language" in 1985, so it became the de facto convention in C++, too.

On 7/9/2019 at 4:32 AM, Shaarigan said:

I use the linker minification in my game engine classes that abstract certain API like filesystem handling, threading and so on

Yes, back in the bad old days lots of people just used an extern declaration whenever they needed a function.  It may work for you.  It may not, because you need to specify some special linkage option (Windows was originalyl all FAR calls using Pascal linkage, because they were on a 286 and a cheap rip-off of the Macintosh Toolbox calls, which were written in Pascal) or calling convention (__cdecl? __fastcall?) or alignment attributes.  They may really be a macro obfuscating a wide or narrow version of a call or some special compiler built-in.  They may change signature from release to release.  You may find success, or you may open up a can of maintenance nightmare.  Good luck.

Share this post


Link to post
Share on other sites
11 minutes ago, Bregma said:

It may work for you.  It may not, because you need to specify some special linkage option

I know and this is a good point of "learn to know your APIs". You need to know the signature and history of whatever you are using. So in my case anything I use are legacy functions in Windows and core features in Linux/ Android for example. LoadLibraryW, CreateThread, OpenFileW are examples of those legacy code that I doubt will ever change in upcomming Windows (10) versions because this is the barebone code of kernel32.dll the whole OS depends on. I totally agree for newer functions but I don't intended to use one yet and it seems that it won't be necessary to do so.

The other point is true, there are still old FAR declarations in the header files as same as special MACOS sections but they seem and my research confirmed that they aren't used anymore and I don't intend to support Systems older than Windows XP, maybe even Windows 7 as lowest supported OS. There those macros are defined to void.

But what I especially like about doing that is (except for linking against kernel32 that is a default dependency in Visual Studio) that the code keeps clean, my namespaces are pretty small and compile times as same as my own analyzer tools run a lot less when not in need to parse the mess of windows.h and it's included header files.

#define SE_WINAPI stdcall
#include <Windows/DataTypes.h> //<-- defines the common WINAPI types WORD, DWORD ...
//#define static_link extern "C"
  
namespace Runtime
{
    typedef FILETIME* LPFILETIME;

    static_link dll_import BOOL SE_WINAPI QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
    static_link dll_import BOOL SE_WINAPI QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
    static_link dll_import void SE_WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime);
}

force_inline int64 SE::System::GetHighResolutionTime()
{
    Runtime::LARGE_INTEGER result;
    Runtime::QueryPerformanceCounter(&result);

    return static_cast<int64>(result.QuadPart);
}
force_inline int64 SE::System::GetClockFrequency()
{
    Runtime::LARGE_INTEGER result;
    Runtime::QueryPerformanceFrequency(&result);

    return static_cast<int64>(result.QuadPart);
}
force_inline uint64 SE::System::GetTimestamp()
{
    Runtime::FILETIME result;
    Runtime::GetSystemTimeAsFileTime(&result);

    return static_cast<uint64>(result.dwHighDateTime) << 32 | result.dwLowDateTime;
}

#undef SE_WINAPI

(Taken from my GitHub)

The only point I needed to use the windows.h header file was for the MemoryBarrier function macro using atomic variable access but I put that into a .cpp file to hide it behind a function also and excluded as many windows.h features as possible.

My design is to have the Runtime namespace to contain any platform/ hardware dependent API call and hide this behind the System namespace that unifies access to these calls. A programer can then either use the System namespace driectly or have the wrapper classes like File or Thread do that for him and he just uses those classes.

This feels like the design I can best work with

Share this post


Link to post
Share on other sites
8 minutes ago, Shaarigan said:

This feels like the design I can best work with

Yes, as I said it may work for you, right now, for what you need.

I would argue it does not constitute sound advice to hand out in general.

Share this post


Link to post
Share on other sites
1 minute ago, Bregma said:

I would argue it does not constitute sound advice to hand out in general

Yes but seemed worth to mention because I didn't know before too 😊

Share this post


Link to post
Share on other sites

I'd just avoid including windows.h in any Header and hide uses inside a few cpp files.

I also find it helpful to order includes from specific to less to library to system to standard headers, to ensure they are not dependent on others coincidentally included beforehand. This also makes your problem less likely.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!