How to deal with warnings about tail-padded arrays in C++? - c++

I'm writing a C++ application which uses a C library that defines a tail-padded structure in one of its headers. Without going into too much details, it looks somewhat like this:
struct MyStruct {
// ... other members
// The last member, a tail-padding array
MyType myBuffer[];
}
I use -Wall -Wextra -Wpedantic -Werror with g++ and -std=c++0x.
Unfortunately, g++ gives me a warning about that array:
error: ISO C++ forbids zero-size array 'myBuffer' [-Wpedantic]
What is the right way to deal with this?
I know I can suppress the warning by adding a pragma to the header myself:
#pragma GCC diagnostic ignored "-Wpedantic"
But that doesn't feel right. What do you guys suggest?

You could
Remove the zero-sized array.
Build without -Wpedantic (possibly only for that file).
Build without -Werror and ignore the warning.
Build the code as C.

Related

How to enable _all_ warnings with -fpermissive from g++?

There seem to be cases where the -fpermissive option results in errors being ignored altogether, rather than "downgraded" to warnings, as widely available documentation suggests.
The -Wall option is clearly not enough. What other options are needed in order to have all such downgraded warnings reported by g++?
An example came up with the Nodejs C++ addon library.
In file included from /opt/nodejs/linux64/8.9.4/include/node/node.h:63:0,
from /opt/nan/linux64/2.9.2/include/nan.h:51,
from /build/ndjs/include/blob.h:59,
from /build/ndjs/src/blob.cpp:2:
/opt/nodejs/linux64/8.9.4/include/node/v8.h: In instantiation of ‘v8::Local<T>::Local(v8::Local<S>) [with S = v8::Integer; T = v8::Int32]’:
/build/src/ndjs/blob.cpp:507:1: required from here
/opt/nodejs/linux64/8.9.4/include/node/v8.h:207:5: error: invalid conversion from ‘v8::Integer*’ to ‘v8::Int32*’ [-fpermissive]
TYPE_CHECK(T, S);
^
Recompiling with -fpermissive (and -Wall, of course) results in a clean compile: no warnings at all. What happened? (i.e. Why?)
The TYPE_CHECK() macro tests for type compatibility in pointer assignments:
#define TYPE_CHECK(T, S) \
while (false) { \
*(static_cast<T* volatile*>(0)) = static_cast<S*>(0); \
}
It fails for downcasts (v8::Int32 is derived from v8::Integer), but somehow succeeds without warnings when -fpermissive is in effect. Shouldn't there be a warning about the static downcast?

VARIADIC MACRO compile error

I want to learn how to use macro.
I simply write a sample but failed to compile on my local g++4.9
#define P(...) printf("13", ##__VA_ARGS__)
int main() {
// your code goes here
P();
return 0;
}
I will get compile error as below
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:4:42: error: expected primary-expression before ')' token
#define P(...) printf("13", ##__VA_ARGS__)
^
main.cpp:7:5: note: in expansion of macro 'P'
P();
^
But the same code can be compiled on ideone....
http://ideone.com/ucEXXz
and also by VS2015.
Is there any reasonable explanation for this?
How can I write a portable macro for all compiler....
Thanks.
In C, functions that take variable arguments require a prototype declaration, while in C++, all functions require a prototype. The declaration for printf can be found in stdio.h.
#include <stdio.h>
#define P(...) printf("13", ##__VA_ARGS__)
int main() {
P();
return 0;
}
The ##__VA_ARGS__ syntax is non-standard. It is a "swallow comma if the __VA_ARGS__ is empty" extension implemented by GCC, and seems to have been adopted by other compilers.
Regarding the behavior of -std=c++14:
The compiler can accept several base standards, such as ‘c90’ or ‘c++98’, and GNU dialects of those standards, such as ‘gnu90’ or ‘gnu++98’. When a base standard is specified, the compiler accepts all programs following that standard plus those using GNU extensions that do not contradict it. For example, -std=c90 turns off certain features of GCC that are incompatible with ISO C90, such as the asm and typeof keywords, but not other GNU extensions that do not have a meaning in ISO C90, such as omitting the middle term of a ?: expression.
GCC documentation for -std=
The ##__VA_ARGS__ extension does not conflict with the standard. What is causing it to be rejected by the coliru site is that the -pedantic flag is set.
Valid ISO C and ISO C++ programs should compile properly with or without this option (though a rare few require -ansi or a -std option specifying the required version of ISO C). However, without this option, certain GNU extensions and traditional C and C++ features are supported as well. With this option, they are rejected.
GCC documentation for -pedantic

Caught set but unused parameters with clang

Is there a way I could catch set but unused variables using clang, something similar to gcc's Werror=unused-but-set-parameter?
I set -Wunused but clang doesn't catch set but unused parameters.
I am not sure if you have tried more than what you have listed, but here is more information on CLANG unused options, using its GCC compatibility:
First, here is what the documentation suggests:
-Wextra -Wunused-but-set-parameter
The following is background reference information:
From HERE:
If you are using the LLVM-GCC or Apple LLVM Compiler build option there are a large number of possible compiler warnings that you can enable/disable. The Clang front end also supports the GCC diagnostic warnings (see http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html) for backwards compatibility.
Following the referenced link in that quote lists several unused options from the GCC family of warnings:
-Wall
This enables all the warnings about constructions that some users consider questionable, and that are easy to avoid (or modify to prevent the warning), even in conjunction with macros. This also enables some language-specific warnings described in C++ Dialect Options and Objective-C and Objective-C++ Dialect Options.
-Wall turns on the following warning flags:
(there are many more, just listing 'unused')
...
-Wunused-function
-Wunused-label
-Wunused-value
-Wunused-variable
...
And finally, just below the last block:
-Wextra
This enables some extra warning flags that are not enabled by -Wall.
(This option used to be called -W. The older name is still supported, but the newer name is more descriptive.)
(again, there are more, just listing _unused variety)
-Wunused-parameter (only with -Wunused or -Wall)
-Wunused-but-set-parameter (only with -Wunused or -Wall)
There is an equivalent warning generated by clang-tidy, integrated from clang-analyzer:
note: Value stored to 'tmp' is never read
warning: Value stored to 'tmp' is never read [clang-analyzer-deadcode.DeadStores]
It looks like LLVM chose to implement some of the GCC warnings as separate tools.
In this website, if you search for 'unused' you can find some flags that you could use. And I think this one is your flag:
clang -Wunused-variable test.c

Standard library header hierarchy

Follow up to my answer to this question: SIGSEGV on declaration
In this question the questioner had a problem with a segmentation fault on some simple code. As it turned out it didn't even compile for me and others. GCC (4.8.1) gave an error due to redeclaration of a variable with name bsearch, which happens to be identical to a function name in std. This resulted in a clash as the code also used using namespace std;. Since the questioner accepted my answer I guess this was somehow related with the runtime error (though strange).
The questioner however said the code would compile fine on codeblocks and others confirmed this. bsearch should be defined in cstdlib, but the code did not include it.
It turned out that gcc includes cstdlib if iostream is included anyway as one can see from the trace:
g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++0x -Wall -Wextra -pedantic -MMD -MP -MF"src/Test.d" -MT"src/Test.d" -o "src/Test.o" "../src/Test.cpp"
../src/Test.cpp:14:27: error: ‘long long int bsearch’ redeclared as different kind of symbol
long long int bsiter,bsearch;
^
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/cstdlib:72:0,
from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/ext/string_conversions.h:41,
from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/bits/basic_string.h:2815,
from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/string:52,
from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/bits/locale_classes.h:40,
src/subdir.mk:18: recipe for target 'src/Test.o' failed
from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/bits/ios_base.h:41,
from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/ios:42,
from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/ostream:38,
from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/iostream:39,
from ../src/Test.cpp:1:
/usr/include/stdlib.h:754:14: error: previous declaration of ‘void* bsearch(const void*, const void*, size_t, size_t, __compar_fn_t)’
extern void *bsearch (const void *__key, const void *__base,
^
make: *** [src/Test.o] Error 1
It does so only in c++0x and c++11 mode.
Is this structure of includes required, allowed or defined at all in the c++ standards? On cplusplus.com I can find that iostream will include ostream and ios, but there is no information about includes further down.
The C++ standard mandates in certain places that another header has to be included (e.g., <iostream> has to include <istream> and <ostream>). Otherwise, the standard allows headers to be included and to make declaration available which are not required to become available from a specific header.
I'd think it would be useful to have a system of headers which make exactly those declarations available that are required to be made available but I'm not aware of that being available. These headers could be without actual definitions and would only be used to verify that all necessary headers are included. It might be better to have the headers be part of an actual implementation but that would make the declarations quite a bit more complex.

Being extremely pedantic with the way your code is compiled

I would like to find out which is the most extreme error checking flag combination for g++ (4.7). We are not using the new C++11 specification, since we need to cross compile the code with older compilers, and these older compilers (mostly g++ 4.0) often cause problems which simply are ignored by the g++4.7.
Right now we use the following set of flags:
-Wall -Wcomment -Wformat -Winit-self -ansi -pedantic-errors \
-Wno-long-long -Wmissing-include-dirs -Werror -Wextra
but this combination does not identify issues such as a double being passed in to a function which expects int, or comparison between signed and unsigned int and this causes the old compiler to choke on it.
I have read through the documentation and -Wsign-compare should be enabled by -Wextra but in practice seems this is not the case, so I might have missed something...
The -ansi is alias for the default standard without GNU extensions. I'd suggest instead being explicit using -std=c++98, but it should be default for g++ -ansi, so not really different.
But generally I've never seen anything that would be accepted by newer gcc and rejected by older gcc on the grounds of being invalid. I suspect any such problem is a bug in the older compiler or it's standard library. Gcc does not have warnings for things that are correct, but didn't work with older versions of it, so you don't have any other option than to test with the older version.
As for the specific issues you mention:
Passing double to function that expects int is not an error. It might be undefined behaviour though. -Wconversion should help.
Comparing signed with unsigned is also well defined, also always worked as defined and in case of equality comparisons actually makes programmers write worse code (comparing unsigned variable larger than int with -1 is something else than comparing it with -1u). So I actually always compile with -Wno-sign-compare.
The compiler should not print warnings for headers found in directories given with -isystem instead of -I, so that should let you silence the warning for Qt headers and keep it enabled for your own code. So you should be able to use -Wconversion.
Use lint or some other static analysis tool to check the code, in addition to compiler. On my Linux distro, apt-get install splint will get splint, maybe check if that has been packaged for your OS for easy installation.