Difference between Linux gcc and Windows Visual Studio for handling static constants?

We built the library on both Linux (gcc) and Windows (Visual Studio), and, as expected, we found minor, but not significant differences between what is needed to get a clean compilation on both platforms.

Today I changed the flag of the gcc compiler to use -fPIC (to enable the creation of a shared library). When we tested the linking of the program with the library, we started getting errors (for the first time), with undefined reference up to 2 static constants that are declared and initialized in the header file (but not in the .cpp file).

I found an https://stackoverflow.com/a/312690/16950/... which seemed to address the problem, explaining that even if the static const initialized in the header file, it still needs to be defined in the code file. And making this change fixed the gcc linker error.

Visual Studio, however, did not like this change and generated multiple definition errors. We had to wrap the definition needed for the preprocessor to make Visual Studio compile easily.

Can someone enlighten me about what the difference is here? (Code excerpt below.)

msg.h

 class msg { public: static const int EMPTY_INT_VALUE = INT_MAX; static const char EMPTY_STRING_VALUE = '\002'; // can't define value in header, defined in cpp file static const double EMPTY_DOUBLE_VALUE; ... } 

msg.cpp

 #include "msg.h" const double msg::EMPTY_DOUBLE_VALUE(DBL_MAX); #ifndef _WIN32 // g++ requires these definitions, vs 2010 doesn't like them const int msg::EMPTY_INT_VALUE; const char msg::EMPTY_STRING_VALUE; #endif 
+4
source share
1 answer

I traced it to section 9.4.2 "Static Data Members" of the C ++ language specification ( INCITS / ISO / IEC 14882-2011 [2012] ):

If the non-volatile const static data element is of the type of an integral or enumeration, its declaration in the class definition may indicate a logical or equal-initializer, in which each initializing clause, which is an assignment expression, is a constant expression (5.19). A static literal data member can be declared in the class definition using the constexpr ; if so, his declaration specifies a logical or equal-initializer, in which each initializing clause, which is an assignment expression, is a constant expression. [Note. In both cases, the term can be displayed in constant expressions. -end note] A member must still be defined in the namespace scope if used in odr (3.2) in the program, and the namespace scope definition must not contain an initializer.

So, for integral types (like int and char in your example) you can initialize the class definition. If you do this, you should also define it in the namespace area (i.e., in your .cpp file) and without an initializer. Elsewhere in this section of the specification, it is stated that declaring a static data element in its class is not a definition and therefore must be accompanied by a definition in the namespace scope that you make in your example.

GCC follows this part of the specification; Visual C ++ does not. I tested Visual Studio 2012.

Here's another discussion of non-compliance with Visual C ++ in this regard. The workaround described here is exactly what you are doing: protect the definition of integral variables, although they use _MSC_VER .

+2
source

Source: https://habr.com/ru/post/1495583/


All Articles