Why does this C++ snippet compile (non-void function does not return a value)
Categories:
Why does this C++ snippet compile? (Non-void function does not return a value)

Explore the surprising behavior of C++ compilers, specifically Visual Studio 2012, when encountering non-void functions that fail to return a value, and understand the implications under the C++11 standard.
One of the fundamental rules in C++ is that a non-void function must return a value. However, you might encounter situations, especially with older compilers like Visual Studio 2012, where a snippet like the one below compiles without error, despite violating this rule. This article delves into why this happens, the compiler's behavior, and the standards that govern such scenarios.
The C++ Standard and Undefined Behavior
The C++ standard explicitly states that if control reaches the end of a non-void function without encountering a return statement, the behavior is undefined. This means anything can happen: the program might crash, return a garbage value, or even appear to work correctly in some cases. Compilers are not required to diagnose this, although many modern compilers issue a warning or error.
Specifically, C++11 (and later standards) strictly defines this as undefined behavior. The absence of a return statement in such a function means there's no specified value to be placed in the return register or stack location for the caller to retrieve.
int getValue() {
// No return statement
}
int main() {
int x = getValue();
// 'x' will contain an indeterminate value
return 0;
}
A non-void function getValue that does not return a value.
Visual Studio 2012 and Compiler Behavior
Older versions of Visual Studio, such as VS2012, were often more lenient or had different default warning levels. In some configurations, they might compile code like the snippet above without emitting an error, or sometimes just a warning that developers might ignore. This doesn't mean the code is correct or safe; it merely means the compiler chose not to enforce the rule strictly as an error.
This leniency can be attributed to historical reasons, optimization strategies, or specific compiler flags. The compiler might simply leave whatever value was last in the return register, or a value from an adjacent stack frame, as the 'returned' value. This is a classic example of undefined behavior manifesting in a seemingly benign way, until it causes hard-to-debug issues.

Control Flow in a Non-Returning Non-Void Function
Modern Compilers and Best Practices
Modern C++ compilers (GCC, Clang, and newer Visual Studio versions) are much stricter by default. They typically issue a warning (e.g., -Wreturn-type in GCC/Clang) or even an error for non-void functions that don't return a value. This stricter enforcement helps developers write more robust and standard-compliant code.
To ensure your code is portable and reliable, always explicitly return a value from non-void functions. Even if the value isn't used, returning a default or placeholder value is better than invoking undefined behavior.
int getMeaningOfLife() {
return 42; // Explicitly return a value
}
int main() {
int answer = getMeaningOfLife();
// 'answer' will reliably be 42
return 0;
}
The getMeaningOfLife function now correctly returns an int value.
/W4 for MSVC, -Wall -Wextra for GCC/Clang) and treat warnings as errors (/WX for MSVC, -Werror for GCC/Clang) in your build process. This catches many potential issues, including missing return statements, before they become runtime problems.