C++ variable-sized object may not be initialized - c++

I have the following simple source
#include <iostream>
int main() {
int nv;
nv = 3;
int arr[nv] = { 0, 2, 5 };
return 0;
}
When compiling with GCC on system 1 I get
error: variable-sized object ‘arr’ may not be initialized.
When compiling with GCC on system 2 I get no errors.
Compilation flags are the same in both cases, see below.
What is the reason for this, and how can I get my code to compile in system 1?
I suspected it was related to gcc version, but I found no information to support this suspicion.
In system 1:
$ g++ --version
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
...
$ make
g++ -MMD -g -g3 -Wall -Wunused -Wuninitialized -Wextra -fmessage-length=0 -std=gnu++11 -c -o obj/arrays_test.o src/arrays_test.cc
...
In system 2:
$ g++ --version
g++ (Ubuntu 5.5.0-12ubuntu1~16.04) 5.5.0 20171010
...
$ make
g++ -MMD -g -g3 -Wall -Wunused -Wuninitialized -Wextra -fmessage-length=0 -std=gnu++11 -c -o obj/arrays_test.o src/arrays_test.cc
...

The problem here is that you're using not one but two extensions.
The first extension, as noted already, is that you're using C99 VLA's in C++. That's a documented GCC extension.
The second extension is that even C99 doesn't allow initializers for VLA's :
C99 §6.7.8 [Initialization]
The type of the entity to be initialized shall be an array of unknown
size or an object type that is not a variable length array type.
(In C11 you'll find this restriction in §6.7.9). But as the linked GCC page shows, this is not an official Gnu extension. The C99 restriction still stands. You'll need to use assignment instead of initialization.

Related

gcc - C++ error "declaration changes meaning" - error appears on linux gcc 11.3, but not on msys2 gcc 12.1. how to force it?

With this code:
enum class profession
{
doctor,
banker
};
class person
{
profession profession;
};
int main()
{
}
on linux (opensuse 15.4 with gcc 11.2), compilation command
g++ -std=c++20 -pedantic -Wall -Wextra -Werror=return-type -Wshadow=local -Wempty-body -fdiagnostics-color -s -Os -o program_gpp program.cpp
I get the error :
error: declaration of ‘profession person::profession’ changes meaning of ‘profession’ [-fpermissive]
while on windows (windows 10 pro, 21h1) / msys2 / mingw-w64 / gcc 12.1, compilation command:
g++ -std=c++20 -pedantic -Wall -Wextra -Werror=return-type -Wshadow=local -Wempty-body -fdiagnostics-color -s -Os program.cpp -o program_gpp.exe
I don't get any warning or error, nothing.
I had already found somewhere that maybe gcc itself is built with different switches for the two platforms, and so its sensibility to some errors changes among them, and this is ok. But since I would like my code to avoid this error and compile everywhere, which gcc switches can I use to force this error also on the gcc on windows / msys2 ? note : I don't want to disable the error on linux (the compiler already tells me that it can be disabled with -fpermissive), I want gcc on windows to give me the error too so that I can fix it there and it will also compile on linux.
Pass -fno-ms-extensions to MSYS2 GCC. This disables some MSVC-esque extensions.

Specifying -std when compiling both C and C++ code

Suppose I have a codebase consisting of both C and C++ code, like so:
t.c:
int derp(void)
{
return 42;
}
t.cpp:
#include <iostream>
extern "C" int derp(void);
int main(void)
{
std::cout << derp() << std::endl;
return 0;
}
With clang(++), I can both compile them in one go, like so:
clang++ -o t -xc++ t.cpp -xc t.c
However, if I now want to use non-standard features from e.g. gnu++14 and invoke the compiler like so:
clang++ -o t -xc++ -std=gnu++14 t.cpp -xc t.c
I am greeted with an error:
error: invalid argument '-std=gnu++14' not allowed with 'C/ObjC'
Unlike -x, -std does not seem to work based on a file level, but to be a global option, because adding -std=c11 like so:
clang++ -o t -xc++ -std=gnu++14 t.cpp -xc -std=c11 t.c
Simply gives me the "inverse" error, so to speak:
error: invalid argument '-std=c11' not allowed with 'C++/ObjC++'
And I know that I can compile each source file into an .o file separately and link them together afterwards (and yes, I'm automating the whole process anyway), but I cannot help but think that compiling with different standards per language should be possible. After all, clang supports compiling files in different languages together, and when doing that it would need separate values for the standards already, or not?
So, is there a way with clang(++) to manually specify standards when compiling both C and C++ code?
You can compile C, and you can compile C++.
You cannot compile as both C and C++.
Compile your C source files with C-appropriate flags.
Then compile your C++ source files with C++-appropriate flags (e.g. -std=gnu14).
Then link the results together to get an executable.
clang -o a.o t.c
clang++ -o b.o t.cpp -std=gnu++14
clang++ -o t a.o b.o
You cannot use the shorthand you've attempted to do both at once. It is designed as a shortcut for when all the flags and all the whatevers are the same. That's despite the magic of -x which sort of gets you close-ish.

Why does gcc produce a different result when bulding from source compared to linking a static library?

I have a single C++14 file, my.cpp, and from within it I'm trying to use a C99 library called open62541. For the latter, both full source open62541.c/.h and a library libopen62541.a exist. In my.cpp, where I include the open62541.h, I'm using C++ specific code (e.g. iostream), so technically I'm mixing C and C++.
I can get my.cpp to compile successfully by referencing the libopen62541.a:
gcc -x c++ -std=c++14 -Wall my.cpp -l:libopen62541.a -lstdc++ -o out
This outputs no warnings, and creates an executable out.
However, if I try to compile using source code only:
gcc -x c++ -std=c++14 -Wall my.cpp open62541.c -lstdc++ -o out
I get a lot of ISO C++ warnings (e.g. "ISO C++ forbids converting a string constant to ‘char'*") and some "jump to label" errors originating from within open62541.c, resulting in compilation failure.
I can get compilation to succeed by using the -fpermissive switch:
gcc -x c++ -std=c++14 -Wall my.cpp open62541.c -lstdc++ -fpermissive -o out
which still outputs a lot of warnings, but creates the executable successfully. However, I'm unsure if doing this is a good idea.
Perhaps worth mentioning is that open62541.h considers C++ at the beginning:
#ifdef __cplusplus
extern "C" {
#endif
Given that .a library, which comes bundled with the open62541 library code, is supposedly built from the same source, why are the first two approaches not consistent in terms of warnings and errors generated? Why does one work and the other doesn't?
Should one method - linking .a vs referring to .c - be preferred to another? I was under impression that they should be equivalent, but apparently they aren't.
Is using -fpermissive in this case more of a hack that could mask potential problems, and should thus be avoided?
The error (and warning) you see are compilation errors (and warning) output by a C++ compiler when compiling C code.
For instance, in C "literal" has type char[] while in C++ it has type const char[].
Would you get a C++ compiler build libopen62541.a from open62541.c, you would see the same errors (warnings). But a C compiler might be OK with it (depending on the state of that C source file).
On the other hand, when you compile my.cpp and links it against libopen62541.a, the compiler doesn't see that offending C code, so no errors (warnings).
From here, you basically have two options:
Use the procompiled library if it suits you as is
g++ -std=c++14 -Wall -Wextra -Werror my.cpp -lopen62541.a -o out
Compile the library's code as a first step if you need to modify it
gcc -Wall -Wextra -Werror -c open62541.c
g++ -std=c++14 -Wall -Wextra -Werror -c my.cpp
g++ open62541.o my.o -o out
gcc -x c++ -std=c++14 -Wall my.cpp open62541.c -lstdc++ -o out
This command forces the C code in open62541.c to be compiled as C++. That file apparently contains constructs that are valid in C but not C++.
What you should be doing is compiling each file as its own language and then linking them together:
gcc -std=gnu11 -Wall -c open62541.c
g++ -std=gnu++14 -Wall -c my.cpp
g++ -o out my.o open62541.o
Wrapping up those commands in an easily repeatable package is what Makefiles are for.
If you're wondering why I changed from the strict -std=c++14 to the loose -std=gnu++14 mode, it's because the strict mode is so strict that it may break the system headers! You don't need to deal with that on top of everything else. If you want a more practical additional amount of strictness, try adding -Wextra and -Wpedantic instead ... but be prepared for that to throw lots of warnings that don't actually indicate bugs, on the third-party code.

clang++ compiling template class with implementation in header

$ make
clang++ -o build/blist.exe src/driver.cpp src/BList.h -O0 -g -Wall -Wno-unused-parameter -Wextra -Wconversion -Wold-style-cast -std=c++14 -pedantic -Wold-style-cast
clang: warning: treating 'c-header' input as 'c++-header' when in C++ mode, this behavior is deprecated [-Wdeprecated]
clang: error: cannot specify -o when generating multiple output files
My template implementation is in BList.cpp, but BList.h includes BList.cpp. That's why I pass the header in as an object. I don't know how to set clang to compile!
My header must be named "BList.h" according to my professor.
These parameters compiles with GCC, but not with Clang.
The error has nothing to do with including BList.cpp in BList.h (though that's a dubious practice by itself).
The problem is that you pass src/BList.h to Clang as if it was a source file. The build instruction should be:
clang++ -o build/blist.exe src/driver.cpp -O0 -g -Wall -Wno-unused-parameter -Wextra -Wconversion -Wold-style-cast -std=c++14 -pedantic -Wold-style-cast
You should update your makefile accordingly.

gcc error with Python C API code - "ISO C++ forbids casting between pointer-to-function and pointer-to-object"

The following code fragment does nothing, but illustrates the problem. It was extracted from some Boost Python code, which uses the Numpy C API. This was tested with the backport of a gcc 4.7 snapshot from Debian unstable to squeeze.
#include <boost/python/object.hpp>
#include <numpy/arrayobject.h>
int main(void)
{
PyObject* obj=0;
npy_int64 val;
PyArray_ScalarAsCtype(obj, &val);
return 0;
}
I'm compiling like this.
g++-4.7 -o warn.o -c -isystem /usr/include/python2.6 -fdiagnostics-show-option -ftemplate-depth-100 -fno-strict-aliasing -ansi -pedantic -Wextra -Wall -Werror -Wno-unused-function -Wc++0x-compat -g -O3 -std=c++11 -I/usr/include/python2.6 warn.cc
warn.cc: In function 'int main()':
warn.cc:8:3: error: ISO C++ forbids casting between pointer-to-function and pointer-to-object [-Werror]
cc1plus: all warnings being treated as errors
The problem is the -pedantic and the PyArray_ScalarAsCtype line of code. Without -pedantic the following compiles without error
g++-4.7 -o warn.o -c -isystem /usr/include/python2.6 -fdiagnostics-show-option -ftemplate-depth-100 -fno-strict-aliasing -ansi -Wextra -Wall -Werror -Wno-unused-function -Wc++0x-compat -g -O3 -std=c++11 -I/usr/include/python2.6 warn.cc
g++-4.7 -o warn warn.o -L/usr/lib/python2.6/config -lpython2.6 -lboost_python
Note: I added the =0 to suppress an uninitialized warning. Like I said, the code doesn't do anything.
I'd like to either suppress or remove the warning and keep the -pedantic flag. From what I've read, there is no error as such here, but this falls within some disputed section of the standard. I don't really understand the issue, or how it pertains to this line of code. The new gcc diagnostics allow one to selectively suppress warnings in a section of code, but they require you to know what specific flag is triggering the warning, and I don't know. Without the -Werror flag I get
warn.cc:8:3: warning: ISO C++ forbids casting between pointer-to-function and pointer-to-object [enabled by default]
In Standard C++, you cannot convert between, say, an int* and int(*)(). Likely, this is what's happening under the hood in your implementation. Most platforms allow it, but not all.
Of course, there is nothing illegal about any library only executing on platforms where it is legal.