Why does `int ;` compile fine in C, but not in C++?
The C standard says
A declaration other than a static_assert declaration shall declare at least a declarator (other than the parameters of a function or the members of a structure or union), a tag, or the members of an enumeration.
C++ says
In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (Clause 9) or enumeration.
A violation of this in either language requires a diagnostic. The standards do not talk about compiler errors or warnings. A warning is a diagnostic.
Why do programs in C compile even when the return statement is missing?
C is an old language and at the time it was introduced, returning integers was common enough to be the default return type of a function. People later started realizing that with more complicated return types, it was best to specify int to be sure you are not forgetting the return type, but in order to maintain backwards compatibility with old code, C could not remove this default behavior. Instead most compilers issue warnings.
If the function reaches the end without a return statement an undefined value is returned except in the main
function, 0 is returned. This has the same reason as above.
/* implicit declaration of printf as: int printf(int); */
/* implicit int type */
main()
{
printf("hello, world\n");
} /* implicit return 0; */
Why does an invalid use of C function compile fine without any warnings?
The compiler should issue a message for this program
int foo() {
return 3;
}
int main() {
int x;
foo(&x);
return x;
}
because the function foo called with an argument though its identifier list is empty. So the program has undefined behavior.
According to the C Standard *6.7.6.3 Function declarators (including prototypes)
)
14 An identifier list declares only the identifiers of the parameters
of the function. An empty list in a function declarator that is part
of a definition of that function specifies that the function has no
parameters. The empty list in a function declarator that is not part
of a definition of that function specifies that no information about
the number or types of the parameters is supplied.
So the program is invalid.
You could make it a valid program the following way
int foo();
int main() {
int x;
foo(&x);
return x;
}
int foo( int *p ) {
return 3;
}
Though the compiler can issue a warning that the parameter p
is not used.
In this case the function declaration that is not its definition means that there is no information about the number and types of parameters.
Opposite to C in C++ this declaration
int foo();
is equivalent to
int foo( void );
Why can I call a function in C without declaring it but not in C++?
The fact that the code "compiles" as a c program doesn't mean you can do it. The compiler should warn about implicit declaration of the function foo()
.
In this particular case implicit declaration would declare an identical foo()
and nothing bad will happen.
But suppose the following, say this is
main.c
/* Don't include any header, why would you include it if you don't
need prototypes? */
int main(void)
{
printf("%d\n", foo()); // Use "%d" because the compiler will
// implicitly declare `foo()` as
//
// int foo()
//
// Using the "correct" specifier, would
// invoke undefined behavior "too".
return 0;
}
Now suppose foo()
was defined in a different compilation unit1 foo.c as
foo.c
double foo()
{
return 3.5;
}
does it work as expected?
You could imagine what would happen if you use malloc()
without including stdio.h, which is pretty much the same situation I try to explain above.
So doing this will invoke undefined behavior2, thus the term "Works" is not applicable in the understandable sense in this situation.
The reason this could compile is because in the very old days it was allowed by the c standard, namely the c89 standard.
The c++ standard has never allowed this so you can't compile a c++ program if you call a function that has no prototype ("declaration") in the code before it's called.
Modern c compilers warn about this because of the potential for undefined behavior that can easily occur, and since it's not that hard to forget to add a prototype or to include the appropriate header it's better for the programmer if the compiler can warn about this instead of suddenly having a very unexplicable bug.
1It can't be compiled in the same file because it would be defined with a different return type, since it was already implicitly declared
2Starting with the fact that double
and int
are different types, there will be undefined behavior because of this.
Why does this program compile fine in C++14 but not in a C++11 compiler?
It works on C++14 and also works on C++11. You're very likely using an out-of-date compiler.
There's a fixed bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50025) for your exact issue (cfr. DR 1288)
C++0x initialization syntax doesn't work for class members of reference type
Quoting from Jonathan Wakely
The original C++11 rules required a temporary to be created there and the reference member binds to that temporary.
Sources: Defect Report 1288
Program without semicolon compiles fine in C not in C++ why?
The semicolon is required by both languages. Specifically, C specifies the declaration of one or more structure members as
struct-declaration:
specifier-qualifier-list struct-declarator-list ;
and C++ specifies the declaration of one or more class member variables as
member-declaration:
attribute-specifier-seq<opt> decl-specifier-seq<opt> member-declarator-list<opt> ;
both of which require a semicolon at the end.
You'll have to ask the compiler writers why their C++ compiler is more strict than their C compiler. Note that the language specifications only require a "diagnostic" if a program is ill-formed, so it's legitimate either to issue a warning and continue compiling as if the semicolon were present, or to issue an error and stop.
It looks like your IDE is using GCC as its compiler; in which case you could use -Werror
to convert warnings into errors, if you'd prefer stricter diagnostics.
Why does auto a=1; compile in C?
auto
is an old C keyword that means "local scope". auto a
is the same as auto int a
, and because local scope is the default for a variable declared inside a function, it's also the same as int a
in this example.
This keyword is actually a leftover from C's predecessor B, where there were no base types: everything was int
, pointer to int
, array of int
.(*) Declarations would be either auto
or extrn
[sic]. C inherited the "everything is int
" as a default rule, so you could declare integers with
auto a;
extern b;
static c;
ISO C got rid of this, but many compilers still accept it for backward compatibility. If it seems unfamiliar, then you should realise that a related rule is at work in
unsigned d; // actually unsigned int
which is still common in modern code.
C++11 reused the keyword, which few if any C++ programmers were using with the original meaning, for its type inference. This is mostly safe because the "everything is int
" rule from C had already been dropped in C++98; the only thing that breaks is auto T a
, which no-one was using anyway. (Somewhere in his papers on the history of the language, Stroustrup comments on this, but I can't find the exact reference right now.)
(*) String handling in B was interesting: you'd use arrays of int
and pack multiple characters in each member. B was actually BCPL with different syntax.
Why does flowing off the end of a non-void function without returning a value not produce a compiler error?
C99 and C++ standards require non-void
functions to return a value, except main
. The missing return statement in main
will be defined (to return 0
). In C++ it's undefined behaviour if execution actually reaches the end of a non-void
function other than main
, while in C it's only UB if the caller uses the return value.
This means functions can look like they might reach the end without returning a value, but actually can't reach the closing }
. John Kugelman's answer shows some examples, like a noreturn function called from one side of an if
. It's only undefined behaviour if execution actually does get to the end without reaching a return
earlier. The rationale includes that checking if every real code path returns a value is quite difficult (without knowing which functions never return), so it's not illegal to compile a function like your example, only to actually call it like your main
does.
As an extension, at least one compiler (MSVC) allows a return value to be set with inline assembly, but most others still require a return statement in functions that use inline asm
.
From C++11 draft:
§ 6.6.3/2
Flowing off the end of a function [...] results in undefined behavior in a value-returning function.
§ 3.6.1/5
If control reaches the end of
main
without encountering areturn
statement, the effect is that of executingreturn 0;
Note that the behaviour described in C++ 6.6.3/2 is not the same in C.
gcc will give you a warning if you call it with -Wreturn-type option.
-Wreturn-type Warn whenever a function is defined with a return-type that
defaults to int. Also warn about any
return statement with no return-value
in a function whose return-type is not
void (falling off the end of the
function body is considered returning
without a value), and about a return
statement with an expression in a
function whose return-type is void.This warning is enabled by -Wall.
Just as a curiosity, look what this code does:
#include <iostream>
int foo() {
int a = 5;
int b = a + 1;
}
int main() { std::cout << foo() << std::endl; } // may print 6
This code has formally undefined behaviour, and in practice it's calling convention and architecture dependent. On one particular system, with one particular compiler, the return value is the result of last expression evaluation, stored in the eax
register of that system's processor, if you disable optimization.
This seems to be a consequence of GCC internals with optimization disabled, because in that case it picks the return-value register if it needs any to implement a statement. With optimization enabled in C++ mode, GCC and clang assume this path of execution is unreachable because it contains undefined behaviour. They don't even emit a ret
instruction, so execution falls into the next function in the .text section. Of course undefined behaviour means that anything could happen.
Related Topics
Warning: Returning Reference to Temporary
Differencebetween C-Like Casting and Functional Casting
Catching "Stack Overflow" Exceptions in Recursive C++ Functions
Tcp/Ip Connection on a Specific Interface
Math Precision Requirements of C and C++ Standard
How to Show Enter Password in the Form of Asterisks(*) on Terminal
How to Read a JSON File Containing Multiple Root Elements
New() Without Delete() Is Undefined Behavior or Merely Memory Leak
Using Maven for C/C++ Projects
Function to Mangle/Demangle Functions
Boost::Spirit Expression Parser
What Is the Meaning of Auto When Using C++ Trailing Return Type
How Are Local and Global Variables Initialized by Default
How to Include Compiler Flags in Visual Studio Code
Get Sum of Values Stored in _M256D with Sse/Avx
Changing the Directory from Inside a C Program Under Windows Using System Command