#include <iostream>
struct Foo { static auto foo() -> int { return 123; } };
int main() {
std::cout << static_cast<Foo*>(nullptr)->foo() << std::endl;
return 0;
}
I DO KNOW that this is not allowed by standard. But, how about specific compiler?
I only care GCC(G++) and Clang.
Is there any guarantee that these two compiler allow this as compiler feature/specification/extension?
I can find this neither in the list of gcc's C++ extensions nor in the corresponding list for clang. So I would say that you have no guarantee that this works for either compiler.
There is nothing saying that this will work. It is up to you, if you decide to use it, to ascertain that it really does work for the actual architecture in which you are using it. And it's important to reflect on the fact that code generation, debug traps for null pointer usage (and such) and optimisation in all compilers is "target system dependent" - so it may well work on x86, but not on MIPS, as an example. Or it may stop working in one way or another in version X+0.0.1 of the compiler.
Having said that, I'd expect this particular example to work perfectly fine on any architecture, because this is not used anywhere.
Note that just because something is undefined, doesn't necessarily mean that it will crash, fail or even "not work exactly as you expect it to". It does, however, allow the compiler to generate whatever code the compiler would like, including something that blows up your computer, formats your hard-drive, etc, etc.
Related
Unlike Java, in C/C++ the following is allowed:
int* foo ()
{
if(x)
return p;
// What if control reaches here?
}
This often causes crashes and it is hard to debug problems. Why doesn't the standard enforce to have a final return for non-void functions? (Compilers generate an error for a wrong return value.)
Is there a flag in GCC or MSVC to enforce this? (something like -Wunused-result)
It is not allowed (undefined behaviour). However, the standard does not require a diagnostic in this case.
The standard doesn't require the last statement to be return because of code like this:
while (true) {
if (condition) return 0;
}
This always returns 0, but a dumb compiler cannot see it. Note that the standard does not mandate smart compilers. A return statement after the while block would be a waste which a dumb compiler would not be able to optimise out. The standard does not want to require the programmer to write waste code just to satisfy a dumb compiler.
g++ -Wall is smart enough to emit a diagnostic on my machine.
Use the -Wall flag in GCC.
warning: control reaches end of non-void function
Or more specifically, -Wreturn-type.
My guess: Because sometimes the programmer knows better than the compiler. With this simple example, it's clear that someting is wrong, but consider a switch of many values, or many checks in general. You, as the coder, know that certain values just will not be passed in to the function, but the compiler doesn't and just hints you, that there might be something wrong.
#include <iostream>
int foo(){
if(false)
return 5;
}
int main(){
int i = foo();
std::cout << i;
}
Note that even warning level 1 on MSVC gives the following warning:
warning C4715: 'foo' : not all control paths return a value
You can convert the warning into an error by using the following compiler options
-Wreturn-type -Werror=return-type.
Check out This link
The obvious answer is: because it's not an error. It's only an error if
x is false and if the caller uses the return value, neither of which
can necessarily be determined by the compiler, at least in the general
case.
In this particular case (returning a pointer), it wouldn't be too
difficult to require a return for all paths; Java does this. In
general, however, it's not reasonable in C++ to require this, since in
C++, you can return user defined types for which it may be impossible to
construct a value (no default constructor, etc.) So we have the
situation where the programmer might not be able to provide a return
in a branch that he or she knows can't be taken, and the compiler can't
determine that the branch can't be taken.
Most compilers will warn in such cases, when it can determine the flow.
All of the ones I've seen also warn in some cases where it's clearly
impossible to fall off the end, however. (Both g++ and VC++ warn about:
int
bar( char ch )
{
switch ( ch & 0xC0 ) {
case 0x00:
case 0x40:
return 0;
case 0x80:
return -1;
case 0xC0:
return 1;
}
}
, at least with the usual options. Although it's quite clear that this
function never falls off the end.)
As far as I remember, Visual Studio 2008 warns you about a "execution path that does not have a return value". It is allowed in the meaning of that "C++ won't stop you from shooting you in the foot". So you are to think, not the compiler.
What the standard says about this kind of programming is that it produces undefined behavior.
Undefined behavior is the joy and pity of C/C++, but it is also a fundamental feature of the language design that allows for many of the low-level optimizations that make C a sort of "high level assembler" (it is not, actually, but just to give you an idea).
So, while redirecting to John's answer about the switch to use with GCC, to know "why" the standard does not prevent that, I would point to a very interesting analysis of undefined behavior and all of its misteries: What Every C Programmer Should Know About Undefined Behavior. It makes for a very instructive reading.
tl;dr: Can it be ensured somehow (e.g. by writing a unit test) that some things are optimized away, e.g. whole loops?
The usual approach to be sure that something is not included in the production build is wrapping it with #if...#endif. But I prefer to stay with C++ mechanics instead. Even there, instead of complicated template specializations I like to keep implementations simple and argue "hey, the compiler will optimize this out anyway".
Context is embedded SW in automotive (binary size matters) with often poor compilers. They are certified in the sense of safety, but usually not good in optimizations.
Example 1: In a container the destruction of elements is typically a loop:
for(size_t i = 0; i<elements; i++)
buffer[i].~T();
This works also for build-in types such as int, as the standard allows the explicit call of the destructor also for any scalar types (C++11 12.4-15). In such case the loop does nothing and is optimized out. In GCC it is, but in another (Aurix) not, I saw a literally empty loop in the disassembly! So that needed a template specialization to fix it.
Example 2: Code, which is intended for debugging, profiling or fault-injection etc. only:
constexpr bool isDebugging = false; // somehow a global flag
void foo(int arg) {
if( isDebugging ) {
// Albeit 'dead' section, it may not appear in production binary!
// (size, security, safety...)
// 'if constexpr..' not an option (C++11)
std::cout << "Arg was " << arg << std::endl;
}
// normal code here...
}
I can look at the disassembly, sure. But being an upstream platform software it's hard to control all targets, compilers and their options one might use. The fear is big that due to any reason a downstream project has a code bloat or performance issue.
Bottom line: Is it possible to write the software in a way, that certain code is known to be optimized away in a safe manner as a #if would do? Or a unit tests, which give a fail if optimization is not as expected?
[Timing tests come to my mind for the first problem, but being bare-metal I don't have convenient tools yet.]
There may be a more elegant way, and it's not a unit test, but if you're just looking for that particular string, and you can make it unique,
strings $COMPILED_BINARY | grep "Arg was"
should show you if the string is being included
if constexpr is the canonical C++ expression (since C++17) for this kind of test.
constexpr bool DEBUG = /*...*/;
int main() {
if constexpr(DEBUG) {
std::cerr << "We are in debugging mode!" << std::endl;
}
}
If DEBUG is false, then the code to print to the console won't generate at all. So if you have things like log statements that you need for checking the behavior of your code, but which you don't want to interact with in production code, you can hide them inside if constexpr expressions to eliminate the code entirely once the code is moved to production.
Looking at your question, I see several (sub-)questions in it that require an answer. Not all answers might be possible with your bare-metal compilers as hardware vendors don't care that much about C++.
The first question is: How do I write code in a way that I'm sure it gets optimized. The obvious answer here is to put everything in a single compilation unit so the caller can see the implementation.
The second question is: How can I force a compiler to optimize. Here constexpr is a bless. Depending on whether you have support for C++11, C++14, C++17 or even the upcoming C++20, you'll get different feature sets of what you can do in a constexpr function. For the usage:
constexpr char c = std::string_view{"my_very_long_string"}[7];
With the code above, c is defined as a constexpr variable. Because you apply it to the variable, you require some things:
Your compiler should optimize the code so the value of c is known at compile time. This even holds true for -O0 builds!
All functions used for calculate c are constexpr and available. (and by result, enforce the behaviour of the first question)
No undefined behaviour is allowed to be triggered in the calculation of c. (For the given value)
The negative about this is: Your input needs to be known at compile time.
C++17 also provides if constexpr which has similar requirements: condition needs to be calculated at compile time. The result is that 1 branch of the code ain't allowed to be compiled (as it even can contain elements that don't work on the type you are using).
Which than brings us to the question: How do I ensure sufficient optimizations for my program to run fast enough, even if my compiler ain't well behaving. Here the only relevant answer is: create benchmarks and compare the results. Take the effort to setup a CI job that automates this for you. (And yes, you can even use external hardware although not being that easy) In the end, you have some requirements: handling A should take less than X seconds. Do A several times and time it. Even if they don't handle everything, as long as it's within the requirements, its fine.
Note: As this is about debug, you most likely can track the size of an executable as well. As soon as you start using streams, a lot of conversions to string ... your exe size will grow. (And you'll find it a bless as you will immediately find commits which add 10% to the image size)
And than the final question: You have a buggy compiler, it doesn't meet my requirements. Here the only answer is: Replace it. In the end, you can use any compiler to compiler your code to bare metal, as long as the linker scripts work. If you need a start, C++Now 2018: Michael Caisse “Modern C++ in Embedded Systems” gives you a very good idea of what you need to use a different compiler. (Like a recent Clang or GCC, on which you even can log bugs if the optimization ain't good enough)
Insert a reference to external data or function into the block that should be verified to be optimised away. Like this:
extern void nop();
constexpr bool isDebugging = false; // somehow a global flag
void foo(int arg) {
if( isDebugging ) {
nop();
std::cout << "Arg was " << arg << std::endl; // may not appear in production binary!
}
// normal code here...
}
In Debug-Builds, link with an implementation of nop() in a extra compilation unit nop.cpp:
void nop() {}
In Release-Builds, don't provide an implementation.
Release builds will only link if the optimisable code is eliminated.
`- kisch
Here's another nice solution using inline assembly.
This uses assembler directives only, so it might even be kind of portable (checked with clang).
constexpr bool isDebugging = false; // somehow a global flag
void foo(int arg) {
if( isDebugging ) {
asm(".globl _marker\n_marker:\n");
std::cout << "Arg was " << arg << std::endl; // may not appear in production binary!
}
// normal code here...
}
This would leave an exported linker symbol in the compiled executable, if the code isn't optimised away. You can check for this symbol using nm(1).
clang can even stop the compilation right away:
constexpr bool isDebugging = false; // somehow a global flag
void foo(int arg) {
if( isDebugging ) {
asm("_marker=1\n");
std::cout << "Arg was " << arg << std::endl; // may not appear in production binary!
}
asm volatile (
".ifdef _marker\n"
".err \"code not optimised away\"\n"
".endif\n"
);
// normal code here...
}
This is not an answer to "How to ensure some code is optimized away?" but to your summary line "Can a unit test be written that e.g. whole loops are optimized away?".
First, the answer depends on how far you see the scope of unit-testing - so if you put in performance tests, you might have a chance.
If in contrast you understand unit-testing as a way to test the functional behaviour of the code, you don't. For one thing, optimizations (if the compiler works correctly) shall not change the behaviour of standard-conforming code.
With incorrect code (code that has undefined behaviour) optimizers can do what they want. (Well, for code with undefined behaviour the compiler can do it also in the non-optimizing case, but sometimes only the deeper analyses peformed during optimization make it possible for the compiler to detect that some code has undefined behaviour.) Thus, if you write unit-tests for some piece of code with undefined behaviour, the test results may differ when you run the tests with and without optimization. But, strictly speaking, this only tells you that the compiler translated the code both times in a different way - it does not guarantee you that the code is optimized in the way you want it to be.
Here's another different way that also covers the first example.
You can verify (at runtime) that the code has been eliminated, by comparing two labels placed around it.
This relies on the GCC extension "Labels as Values" https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
before:
for(size_t i = 0; i<elements; i++)
buffer[i].~T();
behind:
if (intptr_t(&&behind) != intptr_t(&&before)) abort();
It would be nice if you could check this in a static_assert(), but sadly the difference of &&label expressions is not accepted as compile-time constant.
GCC insists on inserting a runtime comparison, even though both labels are in fact at the same address.
Interestingly, if you compare the addresses (type void*) directly, without casting them to intptr_t, GCC falsely optimises away the if() as "always true", whereas clang correctly optimises away the complete if() as "always false", even at -O1.
Calling maininside your program violates the C++ Standard
void f()
{
main(); // an endless loop calling main ? No that's not allowed
}
int main()
{
static int = 0;
std::cout << i++ << std::endl;
f();
}
In a lecture Chandler Carruth, at about '22.40' says
if you've written a compiler test you've written a call to main
How is this relevant or how the fact that the Standard doesn't allow is overcome ?
The point here is that if you write compiler test-code, you probably will want to test calling main with a few different parameter sets and that it is possible to do this, with the understanding of the compiler you are going to test on.
The standard forbids calls to main so that main can have magical code (e.g. the code to construct global objects or to initialize some data structure, zero out global uninitialized POD data, etc.). But if you are writing test code for a compiler, you probably will have an understanding of whether the compiler does this - and if so, what it actually does in such a step, and take that into account in your testing - you could for example "dirty" some global variable, and then call main again and see that this variable is indeed set to zero again. Or it could be that main is indeed not callable in this particular compiler.
Since Chandler is talking about LLVM (and in C terms, Clang), he knows how that compiler produces code for main.
This clearly doesn't apply to "black box testing" of compilers. In such a test-suite, you could not rely on the compiler doing anything in particular, or NOT doing something that would harm your test.
Like ALL undefined behaviour, it is not guaranteed to work in any particular way, but SOMETIMES, if you know the actual implementation of the compiler, it will be possible to exploit that behaviour - just don't consider it good programming, and don't expect it to work in a portable way.
As an example, on a PC, you can write to the text-screen (before the MMU has been configured at least) by doing this:
char *ptr = (char *)0xA0000;
ptr[0] = 'a';
ptr[1] = 7; // Determines the colour.
This, by the standard, is undefined behaviour, because the standard does say that you can only use pointers to allocations made inside the C or C++ runtime. But clearly, you can't allocate memory in the graphics card... So technically, it's UB, but guess what Linux and Windows do during early boot? Write directly to the VGA memory... [Or at least they used to some time ago, when I last looked at it]. And if you know your hardware, this should work with every compiler I'm aware of - if it doesn't, you probably can't use it to write low-level driver code. But it is undefined by the standard, and "UB sanitizer" will probably moan at the code.
Unlike Java, in C/C++ the following is allowed:
int* foo ()
{
if(x)
return p;
// What if control reaches here?
}
This often causes crashes and it is hard to debug problems. Why doesn't the standard enforce to have a final return for non-void functions? (Compilers generate an error for a wrong return value.)
Is there a flag in GCC or MSVC to enforce this? (something like -Wunused-result)
It is not allowed (undefined behaviour). However, the standard does not require a diagnostic in this case.
The standard doesn't require the last statement to be return because of code like this:
while (true) {
if (condition) return 0;
}
This always returns 0, but a dumb compiler cannot see it. Note that the standard does not mandate smart compilers. A return statement after the while block would be a waste which a dumb compiler would not be able to optimise out. The standard does not want to require the programmer to write waste code just to satisfy a dumb compiler.
g++ -Wall is smart enough to emit a diagnostic on my machine.
Use the -Wall flag in GCC.
warning: control reaches end of non-void function
Or more specifically, -Wreturn-type.
My guess: Because sometimes the programmer knows better than the compiler. With this simple example, it's clear that someting is wrong, but consider a switch of many values, or many checks in general. You, as the coder, know that certain values just will not be passed in to the function, but the compiler doesn't and just hints you, that there might be something wrong.
#include <iostream>
int foo(){
if(false)
return 5;
}
int main(){
int i = foo();
std::cout << i;
}
Note that even warning level 1 on MSVC gives the following warning:
warning C4715: 'foo' : not all control paths return a value
You can convert the warning into an error by using the following compiler options
-Wreturn-type -Werror=return-type.
Check out This link
The obvious answer is: because it's not an error. It's only an error if
x is false and if the caller uses the return value, neither of which
can necessarily be determined by the compiler, at least in the general
case.
In this particular case (returning a pointer), it wouldn't be too
difficult to require a return for all paths; Java does this. In
general, however, it's not reasonable in C++ to require this, since in
C++, you can return user defined types for which it may be impossible to
construct a value (no default constructor, etc.) So we have the
situation where the programmer might not be able to provide a return
in a branch that he or she knows can't be taken, and the compiler can't
determine that the branch can't be taken.
Most compilers will warn in such cases, when it can determine the flow.
All of the ones I've seen also warn in some cases where it's clearly
impossible to fall off the end, however. (Both g++ and VC++ warn about:
int
bar( char ch )
{
switch ( ch & 0xC0 ) {
case 0x00:
case 0x40:
return 0;
case 0x80:
return -1;
case 0xC0:
return 1;
}
}
, at least with the usual options. Although it's quite clear that this
function never falls off the end.)
As far as I remember, Visual Studio 2008 warns you about a "execution path that does not have a return value". It is allowed in the meaning of that "C++ won't stop you from shooting you in the foot". So you are to think, not the compiler.
What the standard says about this kind of programming is that it produces undefined behavior.
Undefined behavior is the joy and pity of C/C++, but it is also a fundamental feature of the language design that allows for many of the low-level optimizations that make C a sort of "high level assembler" (it is not, actually, but just to give you an idea).
So, while redirecting to John's answer about the switch to use with GCC, to know "why" the standard does not prevent that, I would point to a very interesting analysis of undefined behavior and all of its misteries: What Every C Programmer Should Know About Undefined Behavior. It makes for a very instructive reading.
Was std::string.npos ever valid? (As opposed to the correct std::string::npos.)
I am seeing it a lot in an old project I'm working on, and it does not compile with VS2010.
Is it something from the pre-standard days?
The C with classes syntax for naming a class member was, in fact, a dot:
class X {
public:
void f();
};
void X.f() // a dot! see D&E 2.3
{
}
However, the :: syntax had not yet been invented. The std namespace didn't exist yet either. Thus the std::string.npos wasn't ever valid as either C with classes or standard C++.
I suspect std::string.npos is purely Microsoft's extension (or a bug?). It might be inspired by the old syntax, and might be not.
No, std::string.npos was never valid, and no, it's not something from the pre-standard days.
I see other answers mentioning that MSVC has allowed that notation.
However, MSVC is not a very compliant compiler. For example, it lets you freely bind a temporary to a reference to non-const. For another example, for Windows GUI subsystem applications you have to use not well-documented switches to make it accept a standard main. Much has improved since Microsoft hired Herb Sutter (and other guy that I don't remember the name of right now) to fix up their monstrous compiler. And in relative terms it has been really great, but in absolute terms, well that compiler is still a bit lacking.
Access to any static member via class name and dot was unfortunately allowed by prior versions of MSVC.
#include <iostream>
struct A
{
static int a;
};
int A::a;
int main()
{
std::cout << A.a;
}
This code is happily accepted by MSVC9.0 with a warning
Warning 1 warning C4832: token '.' is
illegal after UDT 'A'
The C++ standard obviously disallows access to a static member via className.memberName (although it is perfectly legal to access a static member via an object object.staticMemberName).
My common sense tells me that if MSVC is aware that this is not standard and gives a warning, then we can turn that extension off. We go to Project Propertied -> C/C++ -> Language and set Disable Language Extensions to Yes. Do you think anything changes? Of course not, the compiler still accepts the illegal code with the same warning. I sometimes wonder what Disable Language Extensions actually does...