How to correctly set _MSVC_LANG value? - c++

As you may know _MSVC_VALUE determines whether _HAS_CXX17 and _HAS_CXX20 macros are set. Today I tried to compile the following code in Visual Studio 2019 (latest 16.6.4 version):
#include <algorithm>
#include <execution>
#include <vector>
int main()
{
std::vector<int> _vector = { 3, 2, 1 };
std::sort(std::execution::par, _vector.begin(), _vector.end());
return 0;
}
Unfortunately, it throws errors. For example this one:
C3083 'execution': the symbol to the left of a '::' must be a type
When I looked into the <execution> header file I noticed that it doesn't compile because macro _HAS_CXX17 is set to 0.
#if !_HAS_CXX17
#pragma message("The contents of <execution> are available only with C++17 or later.")
#else // ^^^ !_HAS_CXX17 / _HAS_CXX17 vvv
So then I looked at the definition of the _HAS_CXX17 macro which is in the vcruntime.h file:
#if !defined(_HAS_CXX17) && !defined(_HAS_CXX20)
#if defined(_MSVC_LANG)
#define _STL_LANG _MSVC_LANG
#elif defined(__cplusplus) // ^^^ use _MSVC_LANG / use __cplusplus vvv
#define _STL_LANG __cplusplus
#else // ^^^ use __cplusplus / no C++ support vvv
#define _STL_LANG 0L
#endif // ^^^ no C++ support ^^^
#if _STL_LANG > 201703L
#define _HAS_CXX17 1
#define _HAS_CXX20 1
#elif _STL_LANG > 201402L
#define _HAS_CXX17 1
#define _HAS_CXX20 0
#else // _STL_LANG <= 201402L
#define _HAS_CXX17 0
#define _HAS_CXX20 0
#endif // Use the value of _STL_LANG to define _HAS_CXX17 and _HAS_CXX20
#undef _STL_LANG
#endif // !defined(_HAS_CXX17) && !defined(_HAS_CXX20)
To my surprise the value of _MSVC_LANG is set to 201402L. It should be a lot higher. I set the -std=c++17 compilation flag like in this answer. Yeah, it's my answer, which proves it worked back in May.
I tried defining the correct value for the macros myself but they are ignored or it throws some other errors:
#define _MSVC_LANG 201704L
// same code as before
// result: macro is ignored, no change
#define _HAS_CXX17 1
#define _HAS_CXX20 1
// same code as before
// result: 250+ errors like this one:
// E0457 "basic_string_view" is not a function or static data member
Just before the update I installed a separated version of standard library from here. The GCC 10.1.0. version and I put mingw/bin on the system path in Windows 10.
I am not aware that installing gcc could break msvc compiler. Then it might be caused by the update of VS 2019 to version 16.6.4?
I also looked at this question but it's not of any help.
Can anyone report similar problem?
Does anybody know how to fix this and compile code under C++17 with VS 2019 version 16.6.4?

For future readers:
If you have similar issue, double-check that you are changing configuration that you will run then. In my case I was changing all the settings for Release but I tried to run the Debug configuration instead and I somehow didn't notice it.
Steps to change the configuration:
Right click on project
In the top left corner there is a drop-down menu
Select the same configuration you are running

Set the platform to "All Platforms" and then make my changes.
Then they flow through the project correctly.

Related

How to get rid of warnings that precompiler definitions are not definied

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).

Is there an elegant solution for checking whether a preprocessor symbol is defined or not

Since preprocessor don't report an error when checking value of preprocessor's symbol that isn't actually defined (usually due to the lack of #include "some_header.h"), I use this cumbersome three line construction with "defined":
#if !defined(SOME_SYMBOL)
#error "some symbol isn't defined"
#endif
#if SOME_SYMBOL == 1
// Here is my conditionally compiled code
#endif
And the way with "#ifndef" is the same.
Is there a more elegant way to perform this check?
In your construction you could use an else block to skip the check for defined:
#if SOME_SYMBOL == 1
// Here is my conditionally compiled code
#else
// error
#endif
But in principle the comments are right. #if !defined and the shorthand #ifndef are the two available versions.
Currently, you are checking if SOME_SYMBOL is equals to 1. Do you execute different code based on that value ?
If not, you could simply use:
#ifdef SOME_SYMBOL
// Here is my conditionally compiled code
#else
// error
#endif
And now it's a short step to the typical c++ include guards. Copying from that wikipedia link, here is a grandparent.h file:
#ifndef GRANDPARENT_H
#define GRANDPARENT_H
struct foo {
int member;
};
#endif /* GRANDPARENT_H */
Now, even if you end up including this header twice, it will only be executed once.

Error: `#elif with no expression` - happens only on Windows

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.

Is it possible to show the value of a #define at compile-time with ARM RVCT?

Question has been answered with VC and GCC in
How do I show the value of a #define at compile-time?
but is it possible to do it with ARM RVCT?
Actually I can do my own macro2string convertion as RVCT doesn't have stringification support. But I didn't even find "#pragma message" support in RVCT. It seems it has only something like
#pragma diag_error 223
which you must specify a tag, you can not freely output a string.
In fact I work on some legacy code now, here is an simplified example from the code base:
in product_conf.h:
#define VALUE_A 1
in platform_conf.h:
#ifndef VALUE_A
#define VALUE_A 2
#endif
in component_conf.h:
#ifndef VALUE_A
#define VALUE_A 3
#endif
in component.c:
#include product_conf.h
#include platform_conf.h
#include component_conf.h
It is a bit difficult to know VALUE_A is 1 or 2 or 3 when you are reading the component.c, actually in the real cases there can be 4~5 layers configurations and the c files may include or not include some certain conf.h, you have to go through the different header files case by case.
So I thought something like:
/* definition to expand macro then apply to pragma message */
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define VAR_NAME_VALUE(var) #var "=" VALUE(var[[)]]
#pragma message(VAR_NAME_VALUE(VALUE_A))
will help for a quick check, I just make the component and I will find out what is defined in the compiling output. This is doable with GCC, but I want to know how to do similar things with ARM RVCT.
or the only way to do it is:
#if (VALUE_A==1)
#warning "VALUE_A is 1"
#elif (VALUE_A==2)
#warning "VALUE_A is 2"
#elif (VALUE_A==3)
#warning "VALUE_A is 3"
#else
#error "VALUE_A is not properly defined!"
#endif

Determining 32 vs 64 bit in C++

I'm looking for a way to reliably determine whether C++ code is being compiled in 32 vs 64 bit. We've come up with what we think is a reasonable solution using macros, but was curious to know if people could think of cases where this might fail or if there is a better way to do this. Please note we are trying to do this in a cross-platform, multiple compiler environment.
#if ((ULONG_MAX) == (UINT_MAX))
# define IS32BIT
#else
# define IS64BIT
#endif
#ifdef IS64BIT
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif
Thanks.
Unfortunately there is no cross platform macro which defines 32 / 64 bit across the major compilers. I've found the most effective way to do this is the following.
First I pick my own representation. I prefer ENVIRONMENT64 / ENVIRONMENT32. Then I find out what all of the major compilers use for determining if it's a 64 bit environment or not and use that to set my variables.
// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif
Another easier route is to simply set these variables from the compiler command line.
template<int> void DoMyOperationHelper();
template<> void DoMyOperationHelper<4>()
{
// do 32-bits operations
}
template<> void DoMyOperationHelper<8>()
{
// do 64-bits operations
}
// helper function just to hide clumsy syntax
inline void DoMyOperation() { DoMyOperationHelper<sizeof(size_t)>(); }
int main()
{
// appropriate function will be selected at compile time
DoMyOperation();
return 0;
}
Unfortunately, in a cross platform, cross compiler environment, there is no single reliable method to do this purely at compile time.
Both _WIN32 and _WIN64 can sometimes both be undefined, if the project settings are flawed or corrupted (particularly on Visual Studio 2008 SP1).
A project labelled "Win32" could be set to 64-bit, due to a project configuration error.
On Visual Studio 2008 SP1, sometimes the intellisense does not grey out the correct parts of the code, according to the current #define. This makes it difficult to see exactly which #define is being used at compile time.
Therefore, the only reliable method is to combine 3 simple checks:
1) Compile time setting, and;
2) Runtime check, and;
3) Robust compile time checking.
Simple check 1/3: Compile time setting
Choose any method to set the required #define variable. I suggest the method from #JaredPar:
// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
Simple check 2/3: Runtime check
In main(), double check to see if sizeof() makes sense:
#if defined(ENV64BIT)
if (sizeof(void*) != 8)
{
wprintf(L"ENV64BIT: Error: pointer should be 8 bytes. Exiting.");
exit(0);
}
wprintf(L"Diagnostics: we are running in 64-bit mode.\n");
#elif defined (ENV32BIT)
if (sizeof(void*) != 4)
{
wprintf(L"ENV32BIT: Error: pointer should be 4 bytes. Exiting.");
exit(0);
}
wprintf(L"Diagnostics: we are running in 32-bit mode.\n");
#else
#error "Must define either ENV32BIT or ENV64BIT".
#endif
Simple check 3/3: Robust compile time checking
The general rule is "every #define must end in a #else which generates an error".
#if defined(ENV64BIT)
// 64-bit code here.
#elif defined (ENV32BIT)
// 32-bit code here.
#else
// INCREASE ROBUSTNESS. ALWAYS THROW AN ERROR ON THE ELSE.
// - What if I made a typo and checked for ENV6BIT instead of ENV64BIT?
// - What if both ENV64BIT and ENV32BIT are not defined?
// - What if project is corrupted, and _WIN64 and _WIN32 are not defined?
// - What if I didn't include the required header file?
// - What if I checked for _WIN32 first instead of second?
// (in Windows, both are defined in 64-bit, so this will break codebase)
// - What if the code has just been ported to a different OS?
// - What if there is an unknown unknown, not mentioned in this list so far?
// I'm only human, and the mistakes above would break the *entire* codebase.
#error "Must define either ENV32BIT or ENV64BIT"
#endif
Update 2017-01-17
Comment from #AI.G:
4 years later (don't know if it was possible before) you can convert
the run-time check to compile-time one using static assert:
static_assert(sizeof(void*) == 4);. Now it's all done at compile time
:)
Appendix A
Incidentially, the rules above can be adapted to make your entire codebase more reliable:
Every if() statement ends in an "else" which generates a warning or error.
Every switch() statement ends in a "default:" which generates a warning or error.
The reason why this works well is that it forces you to think of every single case in advance, and not rely on (sometimes flawed) logic in the "else" part to execute the correct code.
I used this technique (among many others) to write a 30,000 line project that worked flawlessly from the day it was first deployed into production (that was 12 months ago).
You should be able to use the macros defined in stdint.h. In particular INTPTR_MAX is exactly the value you need.
#include <cstdint>
#if INTPTR_MAX == INT32_MAX
#define THIS_IS_32_BIT_ENVIRONMENT
#elif INTPTR_MAX == INT64_MAX
#define THIS_IS_64_BIT_ENVIRONMENT
#else
#error "Environment not 32 or 64-bit."
#endif
Some (all?) versions of Microsoft's compiler don't come with stdint.h. Not sure why, since it's a standard file. Here's a version you can use: http://msinttypes.googlecode.com/svn/trunk/stdint.h
That won't work on Windows for a start. Longs and ints are both 32 bits whether you're compiling for 32 bit or 64 bit windows. I would think checking if the size of a pointer is 8 bytes is probably a more reliable route.
You could do this:
#if __WORDSIZE == 64
char *size = "64bits";
#else
char *size = "32bits";
#endif
Try this:
#ifdef _WIN64
// 64 bit code
#elif _WIN32
// 32 bit code
#else
if(sizeof(void*)==4)
// 32 bit code
else
// 64 bit code
#endif
Below code works fine for most current environments:
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#define IS64BIT 1
#else
#define IS32BIT 1
#endif
"Compiled in 64 bit" is not well defined in C++.
C++ sets only lower limits for sizes such as int, long and void *. There is no guarantee that int is 64 bit even when compiled for a 64 bit platform. The model allows for e.g. 23 bit ints and sizeof(int *) != sizeof(char *)
There are different programming models for 64 bit platforms.
Your best bet is a platform specific test. Your second best, portable decision must be more specific in what is 64 bit.
Your approach was not too far off, but you are only checking whether long and int are of the same size. Theoretically, they could both be 64 bits, in which case your check would fail, assuming both to be 32 bits. Here is a check that actually checks the size of the types themselves, not their relative size:
#if ((UINT_MAX) == 0xffffffffu)
#define INT_IS32BIT
#else
#define INT_IS64BIT
#endif
#if ((ULONG_MAX) == 0xfffffffful)
#define LONG_IS32BIT
#else
#define LONG_IS64BIT
#endif
In principle, you can do this for any type for which you have a system defined macro with the maximal value.
Note, that the standard requires long long to be at least 64 bits even on 32 bit systems.
People already suggested methods that will try to determine if the program is being compiled in 32-bit or 64-bit.
And I want to add that you can use the c++11 feature static_assert to make sure that the architecture is what you think it is ("to relax").
So in the place where you define the macros:
#if ...
# define IS32BIT
static_assert(sizeof(void *) == 4, "Error: The Arch is not what I think it is")
#elif ...
# define IS64BIT
static_assert(sizeof(void *) == 8, "Error: The Arch is not what I think it is")
#else
# error "Cannot determine the Arch"
#endif
Borrowing from Contango's excellent answer above and combining it with "Better Macros, Better Flags" from Fluent C++, you can do:
// Macro for checking bitness (safer macros borrowed from
// https://www.fluentcpp.com/2019/05/28/better-macros-better-flags/)
#define MYPROJ_IS_BITNESS( X ) MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_##X()
// Bitness checks borrowed from https://stackoverflow.com/a/12338526/201787
#if _WIN64 || ( __GNUC__ && __x86_64__ )
# define MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_64() 1
# define MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_32() 0
# define MYPROJ_IF_64_BIT_ELSE( x64, x86 ) (x64)
static_assert( sizeof( void* ) == 8, "Pointer size is unexpected for this bitness" );
#elif _WIN32 || __GNUC__
# define MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_64() 0
# define MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_32() 1
# define MYPROJ_IF_64_BIT_ELSE( x64, x86 ) (x86)
static_assert( sizeof( void* ) == 4, "Pointer size is unexpected for this bitness" );
#else
# error "Unknown bitness!"
#endif
Then you can use it like:
#if MYPROJ_IS_BITNESS( 64 )
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif
Or using the extra macro I added:
MYPROJ_IF_64_BIT_ELSE( DoMy64BitOperation(), DoMy32BitOperation() );
Here are a few more ways to do what you want in modern C++.
You can create a variable that defines the number of system bits:
static constexpr size_t sysbits = (CHAR_BIT * sizeof(void*));
And then in C++17 you can do something like:
void DoMy64BitOperation() {
std::cout << "64-bit!\n";
}
void DoMy32BitOperation() {
std::cout << "32-bit!\n";
}
inline void DoMySysBitOperation()
{
if constexpr(sysbits == 32)
DoMy32BitOperation();
else if constexpr(sysbits == 64)
DoMy64BitOperation();
/*else - other systems. */
}
Or in C++20:
template<void* = nullptr>
// template<int = 32> // May be clearer, pick whatever you like.
void DoMySysBitOperation()
requires(sysbits == 32)
{
std::cout << "32-bit!\n";
}
template<void* = nullptr>
// template<int = 64>
void DoMySysBitOperation()
requires(sysbits == 64)
{
std::cout << "64-bit!\n";
}
template<void* = nullptr>
void DoMySysBitOperation()
/* requires(sysbits == OtherSystem) */
{
std::cout << "Unknown System!\n";
}
The template<...> is usually not needed, but since those functions will have the same mangling name, we must enforce the compiler to pick the correct ones. Also, template<void* = nullptr> may be confusing ( The other template may be better and more logically correct ), I only used it as a workaround to satisfy the compiler name mangling.
If you can use project configurations in all your environments, that would make defining a 64- and 32-bit symbol easy. So you'd have project configurations like this:
32-bit Debug
32-bit Release
64-bit Debug
64-bit Release
EDIT: These are generic configurations, not targetted configurations. Call them whatever you want.
If you can't do that, I like Jared's idea.
I'd place 32-bit and 64-bit sources in different files and then select appropriate source files using the build system.
I'm adding this answer as a use case and complete example for the runtime-check described in another answer.
This is the approach I've been taking for conveying to the end-user whether the program was compiled as 64-bit or 32-bit (or other, for that matter):
version.h
#ifndef MY_VERSION
#define MY_VERSION
#include <string>
const std::string version = "0.09";
const std::string arch = (std::to_string(sizeof(void*) * 8) + "-bit");
#endif
test.cc
#include <iostream>
#include "version.h"
int main()
{
std::cerr << "My App v" << version << " [" << arch << "]" << std::endl;
}
Compile and Test
g++ -g test.cc
./a.out
My App v0.09 [64-bit]