Just learned here that -Wsequence-point comiplation flag will pop a warning when the code can invoke UB. I tried it on a statement like
int x = 1;
int y = x+ ++x;
and it worked very nicely. Until now I have compiled with gcc or g++ only using -ansi -pedantic -Wall . Do you have any other helpful flags to make the code more safe and robust?
As alk summed up, use these flags:
-pedantic -Wall -Wextra -Wconversion
First, I think you don't want to use the -ansi flag, as suggested in Should I use "-ansi" or explicit "-std=..." as compiler flags?
Secondly, -Wextra seems to be quite useful too, as suggested in -Wextra how useful is it really?
Thirdly, -Wconversion seems also useful, as suggested in Can I make GCC warn on passing too-wide types to functions?
Fourthly, -pedantic is also helpul,
as suggested in What is the purpose of using -pedantic in GCC/G++ compiler?.
Lastly, enabling -Wall should be fine in this case, so I am pretty doubtful about what you said.
Example with gcc:
Georgioss-MacBook-Pro:~ gsamaras$ cat main.c
int main(void)
{
int x = 1;
int y = x+ ++x;
return 0;
}
Georgioss-MacBook-Pro:~ gsamaras$ gcc -Wall main.c
main.c:4:16: warning: unsequenced modification and access to 'x' [-Wunsequenced]
int y = x+ ++x;
~ ^
main.c:4:9: warning: unused variable 'y' [-Wunused-variable]
int y = x+ ++x;
^
2 warnings generated.
Georgioss-MacBook-Pro:~ gsamaras$ gcc -v
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.38)
Target: x86_64-apple-darwin16.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Example with g++, same version:
Georgioss-MacBook-Pro:~ gsamaras$ cp main.c main.cpp
Georgioss-MacBook-Pro:~ gsamaras$ g++ -Wall main.cpp
main.cpp:4:16: warning: unsequenced modification and access to 'x'
[-Wunsequenced]
int y = x+ ++x;
~ ^
main.cpp:4:9: warning: unused variable 'y' [-Wunused-variable]
int y = x+ ++x;
^
2 warnings generated.
Relevant answer of mine, that Wall saves the day once more with a similar problem.
Related
For this struct and function:
typedef struct data_s
{
int i1;
int i2;
} data_t;
void print_data_passed_by_ptr(const data_t *data)
{
printf(" i1 = %i\n"
" i2 = %i\n\n",
data->i1,
data->i2);
}
this works fine in C:
// Print R-value struct passed by ptr
print_data_passed_by_ptr(&(data_t){
.i1 = 7,
.i2 = 8,
});
My C build command is:
gcc -Wall -Wextra -Werror -O3 -std=c17 \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
But, in C++ it fails with
error: taking address of temporary [-fpermissive]
My C++ build command is:
g++ -Wall -Wextra -Werror -O3 -std=c++17 \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
So, I added -fpermissive to my C++ build command:
g++ -Wall -Wextra -Werror -O3 -std=c++17 -fpermissive \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
and now the C++ build fails with this:
error: taking address of temporary [-Werror=permissive]
I tried turning off -Werror=permissive with -Wno-error=permissive (see here for that GCC documentation: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html, and search the page for -Wno-error=), but that's not a valid option. New build cmd I attempted:
g++ -Wall -Wextra -Werror -O3 -std=c++17 -fpermissive -Wno-error=permissive \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
...fails with:
cc1plus: error: -Werror=permissive: no option -Wpermissive
So, how do I solve this to force this C code to build in C++? Either suppressing the warning/error, OR providing some modification to the code other than the one shown just below are acceptable answers. I want the code to compile as C also, not just C++, in the end.
I know I can use "const reference" in C++ instead of ptr, like this, and that's great and all and it might answer somebody else's question, but that's not my question:
void print_data_passed_by_cpp_reference(const data_t& data)
{
printf(" i1 = %i\n"
" i2 = %i\n\n",
data.i1,
data.i2);
}
// Print R-value struct passed by C++ reference
print_data_passed_by_cpp_reference({
.i1 = 9,
.i2 = 10,
});
I also know I can remove -Werror and keep -fpermissive to make it build, with warnings, like this:
eRCaGuy_hello_world/cpp$ g++ -Wall -Wextra -O3 -std=c++17 -fpermissive \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
struct_pass_R_values_by_cpp_reference_and_ptr.c: In function ‘int main()’:
struct_pass_R_values_by_cpp_reference_and_ptr.c:87:5: warning: taking address of temporary [-fpermissive]
});
^
Hello world.
i1 = 7
i2 = 8
i1 = 9
i2 = 10
...but I'd really like to keep -Werror on and make that warning go away.
How to automatically pass an R-value parameter into a function as a const ptr for C and as a const reference for C++
(emphasis added to my original quote)
So, how do I solve this to force this C code to build in C++? Either suppressing the warning/error, OR providing some modification to the code other than the one shown just below are acceptable answers. I want the code to compile as C also, not just C++, in the end.
This works! It is one approach. If there are ways to disable the warning/error in gcc via command-line options I'd still like to know those though.
This is pretty clever I think. It passes the R-value by const ptr for C and by const reference for C++ by using two separate definitions for the print_data() function and the DATA_T macro, depending on the language.
#ifndef __cplusplus
// For C
void print_data(const data_t *data)
{
printf(" i1 = %i\n"
" i2 = %i\n\n",
data->i1,
data->i2);
}
#else
// For C++
void print_data(const data_t& data)
{
printf(" i1 = %i\n"
" i2 = %i\n\n",
data.i1,
data.i2);
}
#endif
#ifndef __cplusplus
// For C
#define DATA_T &(data_t)
#else
// For C++
#define DATA_T // leave empty
#endif
Usage:
// Print R-value struct passed by C++ reference, OR by C ptr, depending on
// whether this code is compiled as C or C++
print_data(DATA_T{
.i1 = 9,
.i2 = 10,
});
Build commands:
# For C
gcc -Wall -Wextra -Werror -O3 -std=c17 \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
# For C++
g++ -Wall -Wextra -Werror -O3 -std=c++17 \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
I am trying to detect the following undefined behavior:
% cat undef.cxx
#include <iostream>
class C
{
int I;
public:
int getI() { return I; }
};
int main()
{
C c;
std::cout << c.getI() << std::endl;
return 0;
}
For some reason all my naive attempts have failed so far:
% g++ -Wall -pedantic -o undef -fsanitize=undefined undef.cxx && ./undef
21971
same goes for:
% clang++ -Weverything -o undef -fsanitize=undefined undef.cxx && ./undef
0
Is there a way to use a magic flag in gcc/clang to report a warning/error for the above code at compile time ? at run time ?
References:
% g++ --version
g++ (Debian 10.2.1-6) 10.2.1 20210110
and
% clang++ --version
Debian clang version 11.0.1-2
Turns out my g++ version seems to handle it just fine, all I was missing is the optimization flag:
% g++ -O2 -Wall -pedantic -o undef -fsanitize=undefined undef.cxx && ./undef
undef.cxx: In function ‘int main()’:
undef.cxx:7:25: warning: ‘c.C::I’ is used uninitialized in this function [-Wuninitialized]
7 | int getI() { return I; }
| ^
0
This is clearly documented upstream:
https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wuninitialized
Because these warnings depend on optimization, the exact variables or
elements for which there are warnings depend on the precise
optimization options and version of GCC used.
Here is upstream 'meta'-bug to track all those related issues:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=24639
I got the following warning when compiling a C++ file :
variables.cpp:10:8: warning: extended initializer lists only available with -std=c++11 or -std=gnu++11
int c{2} ;
This is the file :
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std ;
int main()
{
int a = 0 ;
int b(1) ;
int c{2} ;
string myString = "I am a string !" ;
cout << a+b+c << endl ;
cout << myString << endl ;
return EXIT_SUCCESS ;
}
And this is the command line :
g++ -std=c++0x -Wall -Wextra -Winit-self -Wold-style-cast -Woverloaded-virtual -Wuninitialized -Wmissing-declarations -Winit-self -ansi -pedantic variables.cpp -o variables
I am using g++ 7.4.0 on Ubuntu 18.04.1
I do not want to ignore the warning but to solve it,
Thank you
PS : I tried to change -std=c++0x to -std=c++11 but it did not change anything
Remove -ansi in your command, which is equivalent to -std=c++98 and would overwrite your previous flag -std=c++11. According to C-Dialect-Options,
In C mode, this is equivalent to -std=c90. In C++ mode, it is equivalent to -std=c++98.
Replace -std=c++0x with -std=c++11.
Note that if your compiler supports it, it is recommended to use the lastest c++ standard which is -std=c++17. Using newer c++ standard usually makes your code shorter, more readable and more performant.
You have 2 problem in compilation command line:
The first one is the -ansi in compilation command that implicitly set the standard to the c++98. In you case the -ansi option generate conflict with -std=c++11.
The second one is the -std=c++0x, you have to replace it with -std=c++11.
My environment Arch Linux, gcc 7.2
I'm learning C++ and I'm using keyword constexpr to define a constant, while compile, it give me an error message
error: identifier ‘constexpr’ is a keyword in C++11 [-Werror=c++11-compat]
I can compile my program with default g++, but cannot compile with -std=c++14 and -Werror
The command I'm using is:
g++ -std=c++14 -O2 -Wall -Werror -Wextra -ansi -flto
I believe the -Werror option caused the issue. but what is the issue? can someone tell me please?
#include <iostream>
int main() {
constexpr double yen_dollar = 0.107;
std::cout << yen_dollar << std::endl;
return 0;
}
test.cpp:4:5: error: identifier ‘constexpr’ is a keyword in C++11 [-Werror=c++11-compat]
constexpr double yen_dollar = 0.107;
^~~~~~~~~
test.cpp: In function ‘int main()’:
test.cpp:4:5: error: ‘constexpr’ was not declared in this scope
test.cpp:5:16: error: ‘yen_dollar’ was not declared in this scope
std::cout << yen_dollar << std::endl;
From the GCC documentation §3.4 Options Controlling C Dialect, one can read:
-ansi
In C mode, this is equivalent to -std=c90. In C++ mode, it is equivalent to -std=c++98.
Since, you compiled with
g++ -std=c++14 -O2 -Wall -Werror -Wextra -ansi -flto
-ansi overwrites -std=c++14 with -std=c++98. This is why constexpr is not recognized.
Solution: get rid of the -ansi flag.
Have a look at this piece of C++ code:
class Foo
{
int a;
public: Foo(int b): a(a) {}
};
Obviously, the developer meant to initialize a with b rather than a itself, and this is a pretty hard to spot error.
Clang++ will warn about this possible mistake while GCC won't, even with additional warnings enabled:
$ clang++ -c init.cpp
init.cpp:5:27: warning: field is uninitialized when used here [-Wuninitialized]
public: Foo(int b): a(a) {}
^
$ g++ -Wall -Wuninitialized -Winit-self -c init.cpp
$
Is there any chance of enabling the same output for g++?
Use a newer gcc :-) Seems to work fine for me:
stieber#gatekeeper:~$ g++ -Wall -Wuninitialized -Winit-self -c Test.cpp
Test.cpp: In constructor ‘Foo::Foo(int)’:
Test.cpp:5:9: warning: ‘Foo::a’ is initialized with itself [-Wuninitialized]
stieber#gatekeeper:~$ gcc --version
gcc (Debian 4.7.1-2) 4.7.1