This seems like a trivial thing, but I'm not an expert in C++, and I haven't found a good solution to this online as of yet. I'm suspecting I'm missing some basic coding construct that might solve this issue. I have the following definition in one of my main header files:
static const Foo INVALID_FOO = {};
where Foo is a POD class (it doesn't have constructors, as it's used in a union in a C++03 project). This seems fine, except for sources which include the header but don't use INVALID_FOO, I'm getting the warning:
error: 'Foo::INVALID_FOO' defined but not used [-Werror=unused-variable]
I've tried removing the static but then I get duplicate definitions. I could make this a forward declaration, and define it in a .c file, but then the compiler would need to access it through a reference and would not be able to make any optimizations. I'd also like to not disable the -Wall compiler flag. I'm wondering if there's a good way to do this?
You can suppress the GCC warning like this:
static const Foo INVALID_FOO __attribute__ ((unused)) = {};
Note that unused is correct here, all it does is that it suppresses the warning (and it's still fine to reference the identifier). There is also a used attribute which suppresses the warning and tells GCC to emit the definition in the object file even if the compiler does not see a reference to it in the source code—in most cases, this results in unnecessary code bloat.
You can suppress the warning portably using static_cast<void>(INVALID_FOO); statement.
Also note that static const at global and namespace scope is a bit of tautology - const makes it static, so that static is superfluous.
Related
My version (5.4) of gcc warns about unused static functions, even in a header file when -Wall is used. It doesn't complain if the same functions are defined static inline or simply inline.
For example, the following function in a file unused.h:
static void foo() {}
... when included in a test.cpp file as follows:
#include "unused.h"
Generates the following compiler diagnostic when compiler with -Wall:
In file included from test.cpp:11:0:
unused.h: At global scope:
unused.h:9:13: warning: ‘void foo()’ defined but not used [-Wunused-function]
static void foo() {}
^
It is common practice, as far as I know, to include headers with many utility functions, only a handful of which might be used in any given source file. This behavior means that I get warnings for any functions I don't use which are declared only static.
As a practical matter I can simply change these to static inline to get rid of the warning (or turn off the specific warning entirely, but I do find it useful from time to time), but it seems that large utility functions which won't benefit from inlining1 are more logically declared static2.
As far as I know unused static functions (just like static inline) are simply dropped by gcc when the translation unit is compiled, so they pose no binary size or link-time overhead at all.
Am I missing something here? Is there a good reason that unused static functions are more problematic than static inline?
1 Yes, I'm aware it's a hint only but gcc actually takes the hint in many cases.
2 Or perhaps better, only declared in the header file and defined somewhere else in a .cpp file - but that inhibits header-only use which is sometimes convenient.
The warning is because an unused static function might indicate a logic error: why would you have written such a function if it was never called?
However, it is a common idiom to have static inline functions in a header file. Those functions might only be used by some translation units that include the header. It would be annoying if the compiler gave a warning for a translation unit that didn't happen to use one of the functions.
If you deliberately have an unused static non-inline function, you probably will want to either disable the warning entirely, or use a compiler-specific feature to suppress the warning for that function.
Someone asked, "why would you use static inline anyway?". Well, in new C++ you mostly wouldn't use it. However, in C it is a reasonable thing to do. (This is because static inline means the same thing in ISO C and GNU C; however inline without static behaves differently in ISO C than GNU C, so defaulting to static inline just avoids all those issues with no down-side).
People might use static inline in headers that are to be included from both .c and .cpp files; or perhaps they just carry over that habit from C to C++. In the latter case, IMHO it would be annoying for the compiler to warn about something that, although unnecessary, is not a mistake or a problem either.
For such functions you need to set attribute __attribute__((unused)).
My code mysteriously stop working. I figured out I accidentally wrote int listen; in my main.cpp and used listen in my network.cpp which seems to be trying to call the int as a function instead of the C function. Changing the name of the variable (or making it static) fixed the problem.
Is there any warnings I can turn on so I don't get caught by something like this again? The closest I found was something that suggest I make variables static if they don't need to be extern
Heres code
//a.cpp
#include<cstdio>
int main() { puts("Hello"); }
//b.cpp
int puts;
What you have is an ODR violation. You have two different definitions of puts in two different TUs. The standard (N4713 - C++17 draft) says
§6.2 One-definition rule [basic.def.odr]
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program
outside of a discarded statement (9.4.1); no diagnostic required.
This is of course for C++. C has similar rules.
Because of the "no diagnostic required" the compiler chain is not required to issue errors or warnings for your code.
As far as I know there are no flags on popular compilers to issue error/warnings for ODR violations. This is because of how compilers optimize their parsing. See this great answer for more info on that.
There are some good practices that you can follow to minimize this kind of mistake:
In C++ don't declare symbols at global space. Use namespaces.
In C you can prefix global variables with g_. If you write a library you also add a library prefix to everything global.
(as you've suggested) make symbols that are used only in their TU have internal linkage (declare them static or in an unnamed namespace).
use more meaningful, relevant names. E.g. instead of listen you can name it server_is_listening (or something like that that makes sense for its use).
-Werror=missing-variable-declarations may help. It forces you to use static which avoids this problem or declare the variable elsewhere (ie a header). Including that header in any file that includes the C function will cause an error causing another chance to catch the error
I'm using a shared library that defines inline functions in its header.
Here is a reduced test case, as seen by the compilation unit linking to the library (for the version seen by the library, just replace dllimport by dllexport).
class __declspec(dllimport) MyClass {
public:
int myFunc2();
int myFunc1();
};
inline int MyClass::myFunc2(void) {
return myFunc1();
}
inline int MyClass::myFunc1(void) {
return 0;
}
Compiling this gives the warning:
warning: 'int MyClass::myFunc1()' redeclared without dllimport
attribute after being referenced with dll linkage [enabled by default]
Please note that the order in which the functions are defined is important, as putting the definition of myFunc1 before the definition of myFunc2 results in no warnings.
Note also that this code compiles without warnings under Visual C++. These warnings are specific at least to MinGW, maybe to GCC in general. Edit: it came to my mind that I may have to verify if the warning is not inhibited by one of the flags set by the project.
My questions are then:
Why this behavior ?
Declaring myFunc1 as inline inside the class declaration fixes the problem. Why is that ? It's also against the recommended way of doing things.
Is there another (better ?) way to fix this problem ?
The problem comes about because of some magic in the way that dllimport works which normally means you only need it on the first declaration.
Basically, when you declare a function as dllimport and then later redeclare the function with an identical declaration except for the dllimport, the second declaration implicitly gets the dllimport. If the redeclaration is NOT identical, it doesn't get the implicit dllimport.
So what happens here is you first declare the function as dllimport/non-inline, and then declare it as non-dllimport/inline. Adding an inline to the first declaration fixes the problem, as the second then becomes implicitly dllimport. Alternately, adding a __declspec(dllimport) to the second declaration should fix the problem.
Note that reordering the definitions gets rid of the warning, since the warning is about using it before redeclaring it. With a reorder, you're no longer using it before the redeclaration, so you get no warning, though it will be using the non-dllimport version (ie, it will never use the version of the function from the dll).
Note also, using inline dllimport is dangerous. Any program built against the dll might use the inline function in some places and the non-inline function (from the dll) in others. Even if the two functions are identical NOW, a future version of the dll might change and have a different implementation. At which point the old program might start misbehaving if run with the new version of the dll.
Further information to Chris Dodd's answer:
I tested with MSVC 2017 and MinGW-w64 7.2.0; in both cases, with optimization enabled, the call of myFunc1() from myFunc2 resolved to the inline version, despite the warning. Even if the body of myFunc1 were moved to below main().
So my tentative conclusion is that it is safe to ignore this warning.
In the interest of a clean compile, the only method that seems to work in MinGW-w64 is to mark the function declaration within the class definition as inline. The compiler does not allow applying __declspec(dllimport) to the out-of-class function definition.
I have been unable to determine if there is a warning flag for g++ which will specifically disable this warning.
I'm using a shared library that defines inline functions in its header.
Here is a reduced test case, as seen by the compilation unit linking to the library (for the version seen by the library, just replace dllimport by dllexport).
class __declspec(dllimport) MyClass {
public:
int myFunc2();
int myFunc1();
};
inline int MyClass::myFunc2(void) {
return myFunc1();
}
inline int MyClass::myFunc1(void) {
return 0;
}
Compiling this gives the warning:
warning: 'int MyClass::myFunc1()' redeclared without dllimport
attribute after being referenced with dll linkage [enabled by default]
Please note that the order in which the functions are defined is important, as putting the definition of myFunc1 before the definition of myFunc2 results in no warnings.
Note also that this code compiles without warnings under Visual C++. These warnings are specific at least to MinGW, maybe to GCC in general. Edit: it came to my mind that I may have to verify if the warning is not inhibited by one of the flags set by the project.
My questions are then:
Why this behavior ?
Declaring myFunc1 as inline inside the class declaration fixes the problem. Why is that ? It's also against the recommended way of doing things.
Is there another (better ?) way to fix this problem ?
The problem comes about because of some magic in the way that dllimport works which normally means you only need it on the first declaration.
Basically, when you declare a function as dllimport and then later redeclare the function with an identical declaration except for the dllimport, the second declaration implicitly gets the dllimport. If the redeclaration is NOT identical, it doesn't get the implicit dllimport.
So what happens here is you first declare the function as dllimport/non-inline, and then declare it as non-dllimport/inline. Adding an inline to the first declaration fixes the problem, as the second then becomes implicitly dllimport. Alternately, adding a __declspec(dllimport) to the second declaration should fix the problem.
Note that reordering the definitions gets rid of the warning, since the warning is about using it before redeclaring it. With a reorder, you're no longer using it before the redeclaration, so you get no warning, though it will be using the non-dllimport version (ie, it will never use the version of the function from the dll).
Note also, using inline dllimport is dangerous. Any program built against the dll might use the inline function in some places and the non-inline function (from the dll) in others. Even if the two functions are identical NOW, a future version of the dll might change and have a different implementation. At which point the old program might start misbehaving if run with the new version of the dll.
Further information to Chris Dodd's answer:
I tested with MSVC 2017 and MinGW-w64 7.2.0; in both cases, with optimization enabled, the call of myFunc1() from myFunc2 resolved to the inline version, despite the warning. Even if the body of myFunc1 were moved to below main().
So my tentative conclusion is that it is safe to ignore this warning.
In the interest of a clean compile, the only method that seems to work in MinGW-w64 is to mark the function declaration within the class definition as inline. The compiler does not allow applying __declspec(dllimport) to the out-of-class function definition.
I have been unable to determine if there is a warning flag for g++ which will specifically disable this warning.
I've been refactoring my horrible mess of C++ type-safe psuedo-enums to the new C++0x type-safe enums because they're way more readable. Anyway, I use them in exported classes, so I explicitly mark them to be exported:
enum class __attribute__((visibility("default"))) MyEnum : unsigned int
{
One = 1,
Two = 2
};
Compiling this with g++ yields the following warning:
type attributes ignored after type is already defined
This seems very strange, since, as far as I know, that warning is meant to prevent actual mistakes like:
class __attribute__((visibility("default"))) MyClass { };
class __attribute__((visibility("hidden"))) MyClass;
Of course, I'm clearly not doing that, since I have only marked the visibility attributes at the definition of the enum class and I'm not re-defining or declaring it anywhere else (I can duplicate this error with a single file).
Ultimately, I can't make this bit of code actually cause a problem, save for the fact that, if I change a value and re-compile the consumer without re-compiling the shared library, the consumer passes the new values and the shared library has no idea what to do with them (although I wouldn't expect that to work in the first place).
Am I being way too pedantic? Can this be safely ignored? I suspect so, but at the same time, having this error prevents me from compiling with Werror, which makes me uncomfortable. I would really like to see this problem go away.
You can pass the -Wno-attributes flag to turn the warning off.
(It's probably a bug in gcc?)
It works for me with g++ 4.8.2 the following way:
enum class MyEnum : unsigned int
__attribute__((visibility("default")))
{
One = 1,
Two = 2
};
(change the position of the attribute declaration)