In Visual Studio 2015, #define USE_SQLDB directive doesn't do what I expect.
I have a minimal example to explain the issue
#include "stdafx.h"
#define USE_SQLITE
//#define USE_MYSQL
#define USE_SQLDB (defined(USE_SQLITE) || defined(USE_MYSQL))
int main()
{
#if defined(USE_SQLITE)
puts("SQLITE"); // OK
#endif
#if defined(USE_MYSQL)
puts("MYSQL"); // Grayed out - OK
#endif
// Should expand to defined(USE_SQLITE) || defined(USE_MYSQL)
#if USE_SQLDB
puts("SQLITE or MYSQL"); // Grayed out - NOT OK
#endif
#if defined(USE_SQLITE) || defined(USE_MYSQL)
puts("SQLITE or MYSQL"); // OK
#endif
return 0;
}
I expect the USE_SQLDB to be true, but it isn't.
What's wrong here?
this is simply not valid preprocessor stuff
#define USE_SQLDB (defined(USE_SQLITE) || defined(USE_MYSQL))
you are mixing c and preproc. You need
#if defined(USE_SQLITE) || defined(USE_MYSQL)
#define USE_SQLDB
#endif
It is undefined behavior: Ref
If the defined operator appears as a result of a macro expansion, the
C standard says the behavior is undefined.
and from MSDN:
The defined directive can be used in an #if and an #elif directive,
but nowhere else.
Related
There is a file that I downloaded from the Unity web-site
#pragma once
// Standard base includes, defines that indicate our current platform, etc.
#include <stddef.h>
// Which platform we are on?
// UNITY_WIN - Windows (regular win32)
// UNITY_OSX - Mac OS X
// UNITY_LINUX - Linux
// UNITY_IOS - iOS
// UNITY_TVOS - tvOS
// UNITY_ANDROID - Android
// UNITY_METRO - WSA or UWP
// UNITY_WEBGL - WebGL
#if _MSC_VER
#define UNITY_WIN 1
#elif defined(__APPLE__)
#if TARGET_OS_TV //'TARGET_OS_TV' is not defined, evaluates to 0
#define UNITY_TVOS 1
#elif TARGET_OS_IOS //'TARGET_OS_IOS' is not defined, evaluates to 0
#define UNITY_IOS 1
#else
#define UNITY_OSX 1 //'UNITY_OSX' macro redefined
#endif
#elif defined(__ANDROID__)
#define UNITY_ANDROID 1
#elif defined(UNITY_METRO) || defined(UNITY_LINUX) || defined(UNITY_WEBGL)
// these are defined externally
#elif defined(__EMSCRIPTEN__)
// this is already defined in Unity 5.6
#define UNITY_WEBGL 1
#else
#error "Unknown platform!"
#endif
...
The problem is that when I try to include the file in my XCode project I got a warning (put them in comments)
...
#if TARGET_OS_TV //'TARGET_OS_TV' is not defined, evaluates to 0
#define UNITY_TVOS 1
#elif TARGET_OS_IOS //'TARGET_OS_IOS' is not defined, evaluates to 0
#define UNITY_IOS 1
#else
#define UNITY_OSX 1 //'UNITY_OSX' macro redefined
#endif
...
I tried to use #pragma warning(suppress: 4101) and a few similar approaches, but it doesn't help
UPD
...
#ifdef TARGET_OS_TV
#define UNITY_TVOS 1
#elif TARGET_OS_IOS //'TARGET_OS_IOS' is not defined, evaluates to 0
#define UNITY_IOS 1
#else
#define UNITY_OSX 1
#endif
...
Using ifdef helps to get rid of the first warning, but the second one is still in place
UPD2
...
#ifdef TARGET_OS_TV
#define UNITY_TVOS 1
#elifdef TARGET_OS_IOS //Invalid preprocessing directive
#define UNITY_IOS 1
#else
#define UNITY_OSX 1
#endif
...
You should not use #if to test an undefined macro. The warning implies that you should use #ifdef instead.
You may not define a previously defined macro. You could first undefined the old definition, but that's rarely a good idea.
Using ifdef helps to get rid of the first warning, but the second one is still in place
In c++23 you will be able to use #elifdef instead.
Otherwise, you can use #elif defined(the_macro).
I'm trying to compile a project using a library I made on Windows, using MinGW 4.8.1 x86. The project compiles fine on Linux.
Common.hpp is included before everything else, and defines some macros depending on the current OS. Then ConsoleFmt.hpp is included, and it includes a file depending on the previously defined macros.
I'm getting an error, however - here's the code and the error message:
Common.hpp
#if (__linux || __unix || __posix)
#define SSVU_OS_LINUX
#elif (_WIN64 || _WIN32)
#define SSVU_OS_WINDOWS
#else
#define SSVU_OS_UNKNOWN
#endif
ConsoleFmt.hpp
#include "Common.hpp"
#ifdef SSVU_OS_LINUX
#include "SSVUtils/Core/ConsoleFmt/Internal/ConsoleFmtImplUnix.hpp"
#elif SSVU_OS_WINDOWS
#include "SSVUtils/Core/ConsoleFmt/Internal/ConsoleFmtImplWin.hpp"
#else
#include "SSVUtils/Core/ConsoleFmt/Internal/ConsoleFmtImplNull.hpp"
#endif
Error:
error: #elif with no expression:
#elif SSVU_OS_WINDOWS
Is my code invalid or is there a bug in MinGW? I think I'm using #elif correctly.
#elif is a contraction of #else and #if, not #else and #ifdef, so your line should read:
#elif defined(SSVU_OS_WINDOWS)
Edit: Because undefined macros expand to 0 in #if expressions, you could also use the original variant and define the active macro with a value of 1. (As hvd has just posted and explained.)
The safe solution, IMO, is to define SSVU_OS_* in such a way that it doesn't matter whether you use #if or #ifdef.
#if (__linux || __unix || __posix)
#define SSVU_OS_LINUX 1
#elif (_WIN64 || _WIN32)
#define SSVU_OS_WINDOWS 1
#else
#define SSVU_OS_UNKNOWN 1
#endif
This lets your #ifdef/#elif work already as it is. For consistency, you can then clean that up to
#if SSVU_OS_LINUX
#include "SSVUtils/Core/ConsoleFmt/Internal/ConsoleFmtImplUnix.hpp"
#elif SSVU_OS_WINDOWS
#include "SSVUtils/Core/ConsoleFmt/Internal/ConsoleFmtImplWin.hpp"
#else
#include "SSVUtils/Core/ConsoleFmt/Internal/ConsoleFmtImplNull.hpp"
#endif
but it isn't strictly necessary.
Making sure your macros work without needing #ifdef/defined checks allows for simpler expressions if you combine multiple checks (like you already do with the macros of others: you check multiple using ||).
To explain why it works in Linux but fails in Windows:
#elif (_WIN64 || _WIN32)
If _WIN64 has been defined then it gets replaced, e.g. if these had been defined
#define _WIN64
#define _WIN32
then the first line expands to
#elif ( || )
which would generate an error. However, if those tokens were not defined at all, they get replaced by 0:
#elif (0 || 0)
which is OK.
I have a problem where I can't seem to get conditional #define preprocessors to work correctly. For example:
#define WIN32_BUILD
#ifdef WIN32_BUILD
#define PCH "stdafx.h"
#else
#define PCH "xyz.h"
#endif
#include PCH
If I use this form, the compiler tells me that it can't find 'stdafx.h'. OK, that seems odd, so if I change the code to....
#define WIN32_BUILD
#ifdef WIN32_BUILD
#define PCH "xyz.h"
#else
#define PCH "stdafx.h"
#endif
#include PCH
Then the file defined in PCH gets picked up and everything compiles fine. This seems odd to me, almost like the preprocessor is ignoring the #if directives and just using all the #defines that it encounters.
Obviously I am doing something wrong, and I was hoping that someone could help me understand this.
When a project has the precompiled header feature turned on the preprocessor ignores everything that comes before #include "stdafx.h"
So your #define statements are ignored.
TL:DR; #define defines the symbol, #ifdef tests if the symbol is defined not whether it has a value.
#define WIN32_BUILD
This defines a pre-processor token, WIN32_BUILD. The token has no value. Anywhere you use the token 'WIN32_BUILD' the pre-processor will substitute the empty string, i.e. nothing.
#ifdef WIN32_BUILD
This checks if the pre-processor token WIN32_BUILD is defined. It is, you just defined it.
#ifdef WIN32_BUILD
// true - this code is included.
#define PCH "stdafx.h"
This defines the pre-processor token, PCH, and assigns it the value "stdafx.h"
#else
#define PCH "xyz.h"
#endif
This code is ignored, because WIN32_BUILD was defined.
It looks as though you were expecting 'ifdef' to only evaluate to true if the expression was not defined /to/ something.
#define a
#define b SOMETHING
#ifdef a
// you are expecting this to be ignored
#endif
#ifdef b
// and expecting this not to be ignored
#endif
#ifdef and #if defined(...) do the same thing.
#define a
#define b SOMETHING
#if defined(a) && defined(b)
// this code will be evaluated, both tokens are defined.
#endif
This feature of pre-processor tokens is often used to support conditional functionality:
#if HAVE_CPP11_OVERRIDE_KEYWORD
#define OVERRIDE_FN override
#else
#define OVERRIDE_FN
#endif
struct A {
virtual void foo() {}
};
struct B : public A {
void foo() OVERRIDE_FN {}
};
In the above code, the override keyword is only added if the system supports it (determined outside of the code).
So a compiler with override sees
struct B : public A {
void foo() override {}
};
a compiler without it sees
struct B : public A {
void foo() {}
};
Note: The opposite of "ifdef" is "ifndef":
#define a
#define b SOMETHING
#undef c
//#define d // << we didn't define it.
int main() {
#ifdef a
#pramga message("a is defined")
#else
#pramga message("a is UNdefined")
#endif
#ifdef b
#pragma message("b is defined")
#else
#pramga message("b is UNdefined")
#endif
#ifdef c
#pramga message("c is defined")
#endif
#else
#pramga message("c is UNdefined")
#endif
#ifdef d
#pramga message("d is defined")
#endif
#else
#pramga message("d is UNdefined")
#endif
#ifndef d
#pragma message("d is not defined")
#endif
#ifndef a
#pragma message("a is not defined")
#endif
return 0;
}
You can assign a pre-processor token numeric values and test them with #if
#if _MSC_VER
#define WIN32_BUILD 1
#else
#define WIN32_BUILD 0
#endif
#if WIN32_BUILD
#include <Windows.h>
#endif
But, especially when doing cross-platform programming, people tend to use ifdef variants rather than numeric checks, because the value checks require you to explicitly ensure all of the tokens are defined with a value. It's a lot easier just to only define them when you need them.
I have some C++ code, and want to perform an action if the __APPLE__ or __linux macros are defined.
If I did it as a normal if conditional, it would be easy using ||:
if (something || something) { .. code .. }
But as of what I know there is no || operator for #ifdef statements. How would I check if __APPLE__ or __linux is defined using a single #ifdef statement?
You can't in a single #ifdef would a single #if do instead?
#if defined(__APPLE__) || defined(__linux)
this also works if you prefer
#if defined __APPLE__ || defined __linux
In my C++ there is.
#if defined(__APPLE__) || defined(__linux)
// ...
#endif
I can check predefined value like:
#ifdef SOME_VAR
// Do something
#elif
// Do something 2
#endif
If I have to check 2 values instead of 1. Are there any operator:
#ifdef SOME_VAR and SOME_VAR2
// ...
#endif
Or I have to write:
#ifdef SOME_VAR
#ifdef SOME_VAR2
// At least! Do something
#endif
#endif
The standard short-circuiting and operator (&&) along with the defined keyword is what is used in this circumstance.
#if defined(SOME_VAR) && defined(SOME_VAR2)
/* ... */
#endif
Likewise, the normal not operator (!) is used for negation:
#if defined(SOME_VAR) && !defined(SOME_OTHER_VAR)
/* ... */
#endif
You can use the defined operator:
#if defined (SOME_VAR) && defined(SOME_VAR2)
#endif
#ifdef and #ifndef are just shortcuts for the defined operator.
You can write:
#if defined(SOME_VAR) && defined(SOME_VAR2)
// ...
#endif
#if defined(A) && defined(B)
One alternative is to get away from using #ifdef and just use #if, since "empty symbols" evaluate to false in the #if test.
So instead you could just do
#if SOME_VAR && SOME_OTHER_VAR
// -- things
#endif
But the big side effect to that is that you not only need to #define your variables, you need to define them to be something. E.g.
#define SOME_VAR 1
#define SOME_OTHER_VAR 1
Commenting out either of those #defines will make the above #if test fail (insofar as the enclosed stuff not being evaluated; the compiler will not crash or error out or anything).