I was writing cross platform code in Visual Studio Community, using C++20 and I am stuck on the output of following code:
#define WINDOWS (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
#define UNIX (defined(__unix__) || defined(__unix))
constexpr bool is_unix1()
{
#ifdef UNIX
return true;
#else
return false;
#endif
}
constexpr bool is_unix2()
{
#ifdef defined(UNIX)
return true;
#else
return false;
#endif
}
int main()
{
cout << std::boolalpha << is_unix1() << " " << is_unix2() << endl;
}
When I ran this code in windows, from inside VS Community itself, I got the following output:
true false
Can someone explain why is_unix1()
is evaluated as false
while is_unix2()
is evaluated as true
?
I came to know that defined(...)
is compiler specific, and it is not part of standard C++. But directly using the macro is resulting in strange behavior, and I am stuck on which approach to use here.
defined
is not compiler-specific. It is specified in the C++ standard.
#ifdef defined(UNIX)
is simply not valid syntax and a compiler must diagnose this. #ifdef
must be followed by a single identifier and then a new-line. It conditionally compiles code based on whether or not the identifier is defined as a macro.
#ifdef UNIX
therefore always compiles the then-branch, because you defined UNIX
as a macro beforehand.
What you want seems to be something like
#if (defined(__unix__) || defined(__unix))
#if
conditionally compiles based on a given expression which can include defined
operators, which individually evaluate to 0
or 1
depending on whether the identifier is defined as a macro.
However, you can't hide (defined(__unix__) || defined(__unix))
behind the UNIX
macro and then have it expand in the controlling #if
expression. If such an expansion results in the defined
token, the behavior of the program is undefined.
So what you really want instead of your definition for UNIX
is
#if (defined(__unix__) || defined(__unix))
#define UNIX
#endif
And then later
#ifdef UNIX