Why is C++ more restrictive regarding forward declaration of function prototypes (signatures)? [closed] - c++

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I noticed that C++ is more restrictive than C with regards to declaring function signatures before using them even if function definitions are declared after the function that actually calls them?
I always thought that C is more restrictive but it seems like this is not the case.
Why has the philosophy changed when making the standards for C++ programming language?
For example the following code runs compiles fine on gcc command but outputs an error when trying to compile with g++
#include<stdio.h>
int main()
{
int a=sum(4,6);
printf("%d",a);
return 0;
}
int sum(int a,int b)
{
return a+b;
}
The error is
‘sum’ was not declared in this scope

In older (before C99) C standard, there's a thing called "implicit function declaration" which has been removed since C99.
So if you compile in C90 mode, a compiler has to support that "feature". Whereas in C++, "implicit function declaration" has never been there. So GCC errors out. Your code is not valid in modern C (C99 or later) either.
Compile with stricter compiler switches (e.g. -std=c99 -Wall -Wextra -pedantic-errors) and pay attention to all diagnostics.

I always thought that C is more restrictive but it seems like this is not the case.
You have it backward. In nearly all the places where C++ isn't a superset of C, it is because C++ is more restrictive. The C++ type system is stricter than the C type system, legacy features like the one you tripped over ("implicit declaration") are removed, there are many more reserved words, etc.
It is true that C++ has many more features than C, but you mustn't confuse the number of features a language has with a lack of restrictions. A major aspect of the design philosophy of the ML/Haskell language family is to provide lots and lots of features but also lots and lots of strictness.

C originally allowed functions to be called from the program without having been defined, allowing for them to be "defined later". And then if you didn't define the function, the compiler simply made up a calling convention such as "ok I don't know what this function returns, so lets guess that it returns int". Similar assumptions could be made for the parameters... which you could optionally define the types for. Old "K&R style" C functions looked like
int func (a, b)
int a;
int b;
{
...
}
To force the type of the parameters, you would have to use so-called "prototype format", with a forward declaration like:
int func (int a, int b); // function prototype since the parameter types are explicit
All of the implicit function declaration behavior was plain dangerous nonsense and lead to fatal bugs. Yet this dangerous behavior was only partially phased out in the 1990 years standardization. The compiler was still allowed to make implicit assumptions about the function if no prototype was visible. (For example, this is why malloc used to freak out completely if you forgot to include stdlib.h.)
This is why your code compiles, you are using an old version of gcc (4.x or older) which defaults to -std=gnu90, which uses the 1990 years C standard + non-standard extensions. Newer versions of gcc, 5.0 or later, default to -std=gnu11 which is the current C standard (C11) + non-standard extensions.
C++ never allowed this behavior, and C fixed it too, with the C99 standard in the year 1999. Even if you have an old gcc compiler, you should be able to compile with gcc -std=c99 -pedantic-errors, which means "actually follow the C standard, 1999 years version". Then you get compiler errors if no proper function declaration/definition is visible before calling a function.

There are many reasons. One of them is function overloading:
void func(double);
// void func(int);
int main()
{
func(1);
}
If I uncomment the line with void func(int x);, it will be called, otherwise 1 will be promoted to double and void func(double) will be called.

When a C compiler sees a call to a function that it doesn't know about, it guesses what the return value and the parameter types should be. The return type is guessed as int, and the parameter types are guessed to be the same as the value passed in after applying the "usual promotions".
So if you just call
double result = cube (1);
the compiler guesses that the function "cube" has one argument of type int, and returns int.
What happens if that "guess" is wrong? Tough. You have undefined behaviour, your code may crash or worse.
Because of this "guessing", the call sum (4, 6) is allowed in C, and because the actual function had all the right types (two arguments of type int, return value has type in) it actually works. But this is obviously a very dangerous thing to do.
Because it is so dangerous, C++ doesn't implicit declarations (that is the C++ compiler isn't allowed to guess the argument types. That's why it doesn't compile.
There are a few languages around nowadays where the compiler doesn't need a function to be declared before it is used.

Related

Why can I call a function in C without declaring it but not in C++?

In C++, it is a compiler error to call a function before it is declared. But in C, it may compile.
#include<stdio.h>
int main()
{
foo(); // foo() is called before its declaration/definition
}
int foo()
{
printf("Hello");
return 0;
}
I have tried and know that it is correct but I can't get the reason behind it. Can anyone please explain how the compilation process actually takes place and differs in both the languages.
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.
When C was developed, the function name was all you needed to be able to call it. Matching arguments to function parameters was strictly the business of the programmer; the compiler didn't care if you passed three floats to something that needed just an integer.
However, that turned out to be rather error prone, so later iterations of the C language added function prototypes as a (still optional) additional restriction. In C++ these restrictions have been tightened further: now a function prototype is always mandatory.
We can speculate on why, but in part this is because in C++ it is no longer enough to simply know the function name. There can be multiple functions with the same name, but with different arguments, and the compiler must figure out which one to call. It also has to figure out how to call (direct or virtual?), and it may even have to generate code in case of a template function.
In light of all that I think it makes sense to have the language demand that the function prototype be known at the point where the function is called.
Originally, C had no function prototypes, and C++ did not exist.
If you said
extern double atof();
this said that atof was a function returning double. (Nothing was said about its arguments.)
If you then said
double d = atof("1.3");
it would work. If you said
double d2 = atof(); /* whoops, forgot the argument to atof() */
the compiler would not complain, but something weird would happen if you tried to run it.
In those days, if you wanted to catch errors related to calling functions with the wrong number or type of arguments, that was the job of a separate program, lint, not the C compiler.
Also in those days, if you just called a function out of the blue that the compiler had never heard of before, like this:
int i = atoi("42");
the compiler basically pretended that earlier you had said
extern int atoi();
This was what was called an implicit function declaration. Whenever the compiler saw a call to a function whose name it didn't know, the compiler assumed it was a function returning int.
Fast forward a few years. C++ invents the function prototypes that we know today. Among other things, they let you declare the number and types of the arguments expected by a function, not just its return type.
Fast forward a few more years, C adopts function prototypes, optionally. You can use them if you want, but if you don't, the compiler will still do an implicit declaration on any unknown function call it sees.
Fast forward a few more years, to C11. Now implicit int is finally gone. A compiler is required to complain if you call a function without declaring it first.
But even today, you may be using a pre-C11 compiler that's still happy with implicit int. And a C11-complaint compiler may choose to issue a mere warning (not a compilation-killing error) if you forget to declare a function before calling it. And a C11-compliant compiler may offer an option to turn off those warnings, and quietly accept implicit ints. (For example, when I use the very modern clang, I arrange to invoke it with -Wno-implicit-int, meaning that I don't want warnings about implicit int, because I've still got lots of old, working code that I don't feel like rewriting.)
Why can I call a function in C without declaring it?
Because in C, but not in C++, a function without a prototype is assumed to return an int. This is an implicit declaration of that function. If that assumption turns out to be true (the function is declared later on with return-type of int), then the program compiles just fine.
If that assumption turns out to be false (it was assumed to return an int, but then actually is found to return a double, for example) then you get a compiler error that two functions cannot have the same name. (eg. int foo() and double foo() cannot both exist in the same program)
Note that all of this is C only.In C++, implicit declarations are not allowed. Even if they were, the error message would be different because C++ has function overloading. The error would say that overloads of a function cannot differ only by return type. (overloading happens in the parameter list, not the return-type)

Why is overloading not possible in C? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I know that overloading is not possible in C, and I want to know: why is overloading functions within the class and outside the class treated the same in C++?
Consider this case in C++ where the functions are declared outside the class:
foo()
foo(char c)
foo(int a, int b)
If C++ treats each function header as unique, why can't C do as well?
I think these might be the reason:
Function overloading was introduced in C++, so it is not available in C.
Polymorphism is an OOP concept, but C is not object-oriented.
Are there any reasons for the unavailability of function-overloading in C?
Perhaps the most important reason is the lack of prior art. There are very few examples of features added to C by the standard committee which have neither been popular extensions before nor are necessary to write strictly conforming code.
There is some vaguely defined "spirit of C", the C99 rationale (V5.10) reads (page 3, emph. mine):
Some of the facets of the spirit of C can be summarized in phrases like:
Trust the programmer.
Don't prevent the programmer from doing what needs to be done.
Keep the language small and simple.
Provide only one way to do an operation.
Make it fast, even if it is not guaranteed to be portable.
Further, C tries hard to stay backwards compatible with older revisions; old-style declarations, for example, have been marked obsolescent in C89 but are still part of C11. Ibid, page 2:
Existing code is important, existing implementations are not. A large body of C code exists
of considerable commercial value. Every attempt has been made to ensure that the bulk of this
code will be acceptable to any implementation conforming to the Standard. The C89 Committee
did not want to force most programmers to modify their C programs just to have them accepted
by a conforming translator.
Some differences in C and C++ are at least partly caused by function overloading, for example the type of character constants:
int foo(int);
int foo(char);
...
foo('x');
In C++, this calls foo(char), but in C, the type of 'x' is int, so either the result would be rather surprising, or 'x' needed to be of type char, possibly breaking existing code. Further, you probably want some promotions where they make sense, e.g. if in the last example, the second declaration of foo wasn't given, 'x' would be promoted to int and foo(int) was called. Such rules can become complex in detail (should void * be implicitly converted for function calls?). (Not a hard number, but the chapter about function overloading in the C++ standard (chapter 13) in the n3797 draft covers about 30 pages, chapter ibid. 5.2.2 about function calls is considerably longer than the corresponding C standard part.)
Pretty much every feature of C is necessary for a minimal language (well, modulo historic legacy), there is very little syntactic sugar; function overloading could be considered such (you could name your functions foo_int and foo_char etc and call the correct one explicitly).
The reasons you suggested, are circular (and thus aren't applicable): C did adopt some C++ features (e.g. function prototypes); and function overloading was introduced in C++ because C lacked it (you cannot say "It isn't part of C, because it's part of C++; and it's part of C++, because it isn't part of C"). Same goes for the second suggestion about C and OOP.
What I personally like about C is that it maps rather closely to the machine. It's often easy to see how assembler output generated from C code relates to it. The symbol names are unmangled and can be easily identified. The language is kept simple and minimal. Frankly, I don't understand what people are after when they want to see certain C++ features incorporated into C: We have C++, a language which offers those things, with the ability to write platform-specific, efficient code; why not just use it?
C11 introduced _Generic, which may be of interest for you.
You may find some interesting point in C99 rationale 7.22/25 Type-generic math
<tgmath.h> :
The ability to overload on integer as well as floating types would
have been useful for some functions, for example copysign. Overloading
with different numbers of arguments would have allowed reusing names,
for example remainder for remquo. However, these facilities would have
complicated the specification; and their natural consistent use, such
as for a floating abs or a two-argument atan, would have introduced
further inconsistencies with C89 for insufficient benefit.
Also C11 Standard introduced type _Generic macros, that allows to some sort of overloading, in sense that different types may be handled as function-like macros arguments.
I would say the first and foremost reason C doesn't have function overloading is that C does not mangle function names:
Every function in C is translated to a symbol with the same name while in C++ the name gets mangled.
An example:
Take your functions:
void foo()
void foo(char c)
void foo(int a, int b)
The symbol names as mangled by the C++ code will look the following:
void foo() = _Z3foov
void foo(char c) = _Z3fooc
void foo(int a,int b) = _Z3fooii
While in C code this will translate to:
void foo() = foo
Bottom line - C++ allows name mangling, so the compiler "changes" the function names and all references to three distinct names
C does not allow name mangling at the latest standard (and I doubt this will ever change), so such a solution is just not possible.

C vs C++ function questions

I am learning C, and after starting out learning C++ as my first compiled language, I decided to "go back to basics" and learn C.
There are two questions that I have concerning the ways each language deals with functions.
Firstly, why does C "not care" about the scope that functions are defined in, whereas C++ does?
For example,
int main()
{
donothing();
return 0;
}
void donothing() { }
the above will not compile in a C++ compiler, whereas it will compile in a C compiler. Why is this? Isn't C++ mostly just an extension on C, and should be mostly "backward compatible"?
Secondly, the book that I found (Link to pdf) does not seem to state a return type for the main function. I check around and found other books and websites and these also commonly do not specify return types for the main function. If I try to compile a program that does not specify a return type for main, it compiles fine (although with some warnings) in a C compiler, but it doesn't compile in a C++ compiler. Again, why is that? Is it better style to always specify the return type as an integer rather than leaving it out?
Thanks for any help, and just as a side note, if anyone can suggest a better book that I should buy that would be great!
Firstly, why does C "not care" about the scope that functions are defined in, whereas C++ does?
Actually, C does care. It’s just that C89 allows implicitly declared functions and infers its return type as int and its parameters from usage. C99 no longer allows this.
So in your example it’s as if you had declared a prototype as
int dosomething();
The same goes for implicit return types: missing return types are inferred as int in C89 but not C99. Compiling your code with gcc -std=c99 -pedantic-errors yields something similar to the following:
main.c: In function 'main':
main.c:2:5: error: implicit declaration of function 'donothing' [-Wimplicit-function-declaration]
main.c: At top level:
main.c:5:6: error: conflicting types for 'donothing'
main.c:2:5: note: previous implicit declaration of 'donothing' was her
For the record, here’s the code I’ve used:
int main() {
donothing();
return 0;
}
void donothing() { }
It's because C++ supports optional parameters. When C++ sees donothing(); it can't tell if donothing is:
void donothing(void);
or
void donothing(int j = 0);
It has to pass different parameters in these two cases. It's also because C++ is more strongly typed than C.
int main() {
donothing();
return 0;
}
void donothing() { }
Nice minimum working example.
With gcc 4.2.1, the above code gets a warning regarding the conflicting types for void donothing() with default compiler settings. That's what the C89 standard says to do with this kind of problem. With clang, the above code fails on void donothing(). The C99 standard is a bit stricter.
It's a good idea to compile your C++ code with warnings enabled and set to a high threshold. This becomes even more important in C. Compile with warnings enabled and treat implicit function declarations as an error.
Another difference between C and C++: In C++ there is no difference between the declarations void donothing(void); and void donothing(); There is a huge difference between these two in C. The first is a function that takes no parameters. The latter is a function with an unspecified calling sequence.
Never use donothing() to specify a function that takes no arguments. The compiler has no choice but to accept donothing(1,2,3) with this form. It knows to reject donothing(1,2,3) when the function is declared as void donothing(void).
he above will not compile in a C++ compiler, whereas it will compile in a C compiler. Why is this?
Because C++ requires a declaration (or definition) of the function to be in scope at the point of the call.
Isn't C++ mostly just an extension on C
Not exactly. It was originally based on a set of C extensions, and it refers to the C standard (with a few modifications) for the definitions of the contents of standard headers from C. The C++ "language itself" is similar to C but is not an extension of it.
and should be mostly "backward compatible"?
Emphasis on "mostly". Most C features are available in C++, and a lot of the ones removed were to make C++ a more strictly typed language than C. But there's no particular expectation that C code will compile as C++. Even when it does, it doesn't always have the same meaning.
I check around and found other books and websites and these also commonly do not specify return types for the main function
The C and C++ standards have always said that main returns int.
In C89, if you omit the return type of a function it is assumed to be int. C++ and C99 both lack this implicit int return type, but a lot of C tutorial books and tutorials (and compilers and code) still use the C89 standard.
C has some allowances for implementations to accept other return types, but not for portable programs to demand them. Both languages have a concept of a "freestanding implementation", which can define program entry and exit any way it likes -- again, because this is specific to an implementation it's not suitable for general teaching of C.
IMO, even if you're going to use a C89 compiler it's worth writing your code to also be valid C99 (especially if you have a C99 compiler available to check it). The features removed in C99 were considered harmful in some way. It's not worth even trying to write code that's both C and C++, except in header files intended for inter-operation between the languages.
I decided to "go back to basics" and learn C.
You shouldn't think of C as a prerequisite or "basic form" of C++, because it isn't. It is a simpler language, though, with fewer features for higher-level programming. This is often cited as an advantage of C by users of C. And an advantage of C++ by users of C++. Sometimes those users are the same people using the languages for different purposes.
Typical coding style in C is different from typical coding style in C++, and so you might well learn certain basics more readily in C than in C++. It is possible to learn low-level programming using C++, and the code you write when you do so may or may not end up looking a lot like C code.
So, what you learn while learning C may or may not inform the way you write C++. If it does, that may or may not be for the better.
C++ has changed these rules on purpose, to make C++ a more typesafe language.
C.1.4 Clause 5: expressions [diff.expr]
5.2.2
Change: Implicit declaration of functions is not allowed
Rationale: The type-safe nature of C++.
Effect on original feature: Deletion of semantically well-defined feature. Note: the original feature was
labeled as “obsolescent” in ISO C.
Difficulty of converting: Syntactic transformation. Facilities for producing explicit function declarations
are fairly widespread commercially.
How widely used: Common.
You can find other similar changes in appendix C of this Draft C++ standard
Isn't C++ mostly just an extension on C
No. If you think of C++ as "C with Classes", you're doing it very, very wrong. Whilst strictly, most valid C is valid C++, there's virtually no good C that's good C++. The reality is that good C++ code is vastly different to what you'd see as good C code.
Firstly, why does C "not care" about the scope that functions are
defined in, whereas C++ does?
Essentially, because not enforcing the same rules as C++ makes doing this in C hideously unsafe and in fact, nobody sane should ever do that. C99 tightened this up, along with implicit-int and other defects in the C language.

Why is gcc's option "-Wstrict-prototypes" not valid for C++?

Here is a warning I, and lots of people out there on the web, see when running gcc on C++ code:
cc1plus: warning: command line option "-Wstrict-prototypes" is valid for Ada/C/ObjC but not for C++
The warning text is very clear: 'C++' is not in the set [Ada/C/ObjC ], so I have no question at all about why gcc gives this warning when compiling C++ code. (FYI the reason we have this flag turned on in spite of having C++ code is because it's mostly C code, we have chosen a strict (high level of) warning options list, but we've added a bit of C++ code.
My question is: Why isn't this warning valid for C++?
The gcc documentation for the warning option, from http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Warning-Options.html, is:
-Wstrict-prototypes (C and Objective-C only) Warn if a function is declared or defined without specifying the argument types. (An
old-style function definition is permitted without a warning if
preceded by a declaration which specifies the argument types.)
Now I just know I'm forgetting something obvious about C++, but doesn't C++ also require specifying argument types for functions in a prototype? True that those function prototypes are often in class declarations because the functions are often member functions, but aren't prototypes nevertheless required? Or even if they're just good practice, then why wouldn't gcc offer support by this option? Or if not, by a parallel option for C++?
I suppose it's becuase C++ requires strict prototypes as part of the language, so the option is superfluous. Why that makes it so GCC needs to complain about it is beyond me.
I have that option set in my build script for small sample/test C or C++ programs, and the warning kind of irritates me - it seems like there's no reason to warn just because the default behavior for a language is what I'm asking for. But it's there, so one day when it irritates me enough I'll fix my script to not bother with that option for C++ builds.
It's required by the C++ standard so there's no meaning of turning it on or off: It's always on in the language.
It is implicit in C++ because declaring/defining a function without specifying the argument types is illegal C++ by the standard (yes, this is one of the differences between C and C++ which makes C++ not a true superset).
This is legal C99, but not legal C++03:
void foo(x, y)
int x;
char *y;
{
// ...
}
GCC gives a warning for this in C if compiled with -Wstrict-prototypes.
Another interesting special case:
extern int foo();
By C semantics this declaration specifies an incomplete type for foo, as a function where the number and type of arguments remains unspecified. This is nevertheless a fully valid declaration in C99/C11; however -Wstrict-prototypes forces a warning for this valid declaration in C.
By C++ semantics, this declaration specifies a complete type for foo, as a function that takes no arguments (i.e., it is equivalent to extern int foo(void)). Hence -Wstrict-prototypes is not relevant for this case in C++.

How does this function definition work?

I generated a hash function with gperf couple of days ago. What I saw for the hash function was alien to me. It was something like this (I don't remember the exact syntax) :
unsigned int
hash(str, size)
register char* str;
register unsigned int size;
{
//Definition
}
Now, when I tried to compile with a C++ compiler (g++) it threw errors at me for not having str and size declared. But this compiled on the C compiler (gcc). So, questions:
I thought C++ was a superset of C. If its so, this should compile with a C++ compiler as well right?
How does the C compiler understand the definition? str and size are undeclared when they first appear.
What is the purpose of declaring str and size after function signature but before function body rather than following the normal approach of doing it in either of the two places?
How do I get this function to compile on g++ so I can use it in my C++ code? Or should I try generating C++ code from gperf? Is that possible?
1. C++ is not a superset, although this is not standard C either.
2/3. This is a K&R function declaration. See What are the major differences between ANSI C and K&R C?
.
4. gperf does in fact have an option, -L, to specify the language. You can just use -L C++ to use C++.
The Old C syntax for the declaration of a function's formal arguments is still supported by some compilers.
For example
int func (x)
int x
{
}
is old style (K&R style) syntax for defining a function.
I thought C++ was a superset of C. If its so, this should compile with a C++ compiler as well right?
Nopes! C++ is not a superset of C. This style(syntax) of function declaration/definition was once a part of C but has never been a part of C++. So it shouldn't compile with a C++ compiler.
This appears to be "old-school" C code. Declaring the types of the parameters outside of the parentheses but before the open curl-brace of the code block is a relic of the early days of C programming (I'm not sure why but I guess it has something to do with variable management on the stack and/or compiler design).
To answer your questions:
Calling C++ a "superset" of C is somewhat a misnomer. While they share basic syntax features, and you can even make all sorts of C library calls from C++, they have striking differences with respect to type safety, warnings vs. errors (C is more permissible), and compiler/preprocessor options.
Most contemporary C compilers understand legacy code (such as this appears to be). The C compiler holds the function parameter names sort of like "placeholders" until their type can be declared immediately following the function header name.
No real "purpose" other than again, this appears to be ancient code, and the style back in the day was like this. The "normal" approach is IMO the better, more intuitive way.
My suggestion:
unsigned int hash(register char *str, register unsigned int size)
{
// Definition
}
A word of advice: Consider abandoning the register keyword - this was used in old C programs as a way of specifying that the variable would be stored in a memory register (for speed/efficiency), but nowadays compilers are better at optimizing away this need. I believe that modern compilers ignore it. Also, you cannot use the & (address of) operator in C/C++ on a register variable.