Consider this C program:
int main()
{
puts("Hello world!");
return 0;
}
This compiles and runs fine and as far as I understand, is legal C89. However, I'm not 100% sure about that. Compiling in C99 mode with clang informs me that implicit declaration of function 'puts' is invalid in C99 (which makes me think that the C standard must have changed in C99 to make implicit function declaration illegal, which is what I'm trying to confirm).
Is implicit function declaration legal in C89? (even if it's a bad idea to do it (unless your in an obfuscated C code challenge))
Is implicit function declaration legal in C89?
Yes. From section 3.3.2.2:
If the expression that precedes the parenthesized argument list in
a function call consists solely of an identifier, and if no
declaration is visible for this identifier, the identifier is
implicitly declared exactly as if, in the innermost block containing
the function call, the declaration
extern int identifier();
appeared.
Implicit declaration of function is legal in C89, but is removed in C99. This can be confirmed in C11(ISO/IEC 9899:201x) standard.
In the C11 Forward section, it lists all the major changes in the third edition(i.e, C11) and the second edition(i.e, C99), one of which is:
Major changes in the second edition included:
...
— remove implicit function declaration
Also in Rationale for International Standard Programming Languages C §6.5.2.2 Function calls
A new feature of C99: The rule for implicit declaration of functions has been removed in C99. The effect is to guarantee the production of a diagnostic that will catch an additional category of programming errors. After issuing the diagnostic, an implementation may choose to assume an implicit declaration and continue translation in order to support existing programs that exploited this feature.
Related
If "a function" were compiled separately, the mismatch would not be detected, "the function" would return a double that main would treat as an int... In the light of what we have said about how declarations must match definitions this might seems surprising. The reason a mismatch can happen is that if there is no function prototype, a function is implicitly declared by its first appearance in an expression, such as
sum += "the function"(line);
If a name that has not been previously declared occurs in an expression and is followed by a left parenthesis, it is declared by context to be a function name, the function is assumed to return an int, and nothing is assumed about its arguments.
I apologize beforehand for the ambiguous question, but what does this mean?
By the way this is page 73 chapter 4.3 from Brian W. Kernighan and Dennis M. Ritchie's C Programming Language book, 2nd edition.
K&R2 covers the 1989/1990 version of the language. The current ISO C standard, published in 1999 2011, drops the "implicit int" rule, and requires a visible declaration for any function you call. Compilers don't necessarily enforce this by default, but you should be able to request more stringent warnings -- and you definitely should. In well-written new code, the rule is irrelevant (but it is necessary to understand it).
An example: the standard sqrt() function is declared in <math.h>:
double sqrt(double);
If you write a call without the required #include <math.h>:
double x = 64.0;
double y = sqrt(x);
a C90 compiler will assume that sqrt returns int -- and it will generate code to convert the result from int to double. The result will be garbage, or perhaps a crash.
(You could manually declare sqrt yourself, but that's the wrong solution.)
So don't do that. Always include whatever header is required for any function you call. You might get away with calling an undeclared function if it does return int (and if your compiler doesn't enforce strict C99 or C11 semantics, and if a few other conditions are satisfied), but there's no good reason to do so.
Understanding the "implicit int" rule is still useful for understanding the behavior of old or poorly written code, but you should never depend on it in new code.
Function prototypes were introduced into the language late.
Before prototypes, the compiler would assume that every argument passed to every unknown function should be passed as an integer and would assume that the return value was also an integer.
This worked fine for the few cases where it was correct, but meant people had to write programs in an awkward order so that functions would never rely on unknown functions that did not match this expectation.
When prototypes were introduced into C89 (aka ANSI C or ISO C), the prototypes allow the compiler to know exactly what types of arguments are expected and what types of results will be returned.
It is strongly recommended that you use function prototypes for all new code; when working on an entirely old code base, the prototypes might be harmful. (Or, if the code must be compilable on a pre-ANSI C compiler, then you might wish to leave off the prototypes so it can be built on the ancient software. gcc is the only place I've seen this in a long time.)
It's just stating that if the compiler comes across code that calls an unknown function, then it implicitly treats it as if it had already seen a declared prototype of the form int unknown();
Here is sample code:
#include <ctype.h>
int main(void)
{
isalpha("X");
}
My question is: Is this code a constraint violation? Equivalently, is an implementation non-conforming if it does not issue a diagnostic?
Motivation: Multiple major compilers don't warn for this code, even in conforming code. C11 6.5.2.2/2 covers that passing char * to a function with prototype expecting int is a constraint violation.
However it is not clear to me whether the provisions in 7.1.4 allowing a library function to be additionally defined as a macro supersede the requirement of 6.5.2.2/2. Footnote 187 suggests that the macro hides the prototype, but footnotes are non-normative.
The code (isalpha)("X"); does give a diagnostic of course.
I think the key here is whether isalpha is allowed to be defined as a macro or not. C11 7.1.4 briefly mentions
Any function declared in a header may be additionally implemented as a function-like macro defined in the header
although this chapter is mostly concerned with naming collisions and multi-threading issues etc. On the other hand, C11 7.4 says:
The header declares several functions useful for classifying and mapping characters.
and C11 7.4.1.2:
int isalpha(int c);
The isalpha function...
My take is that isalpha is to be regarded as a function. Or if implemented as a macro, some manner of type check must be ensured by the implementation.
Given that it is a function, it is pretty clear from there. For all functions, the rules for function call are specified in C11 6.5.2.2:
If the expression that denotes the called function has a type that does include a prototype,
the arguments are implicitly converted, as if by assignment, to the types of the
corresponding parameters, taking the type of each parameter to be the unqualified version
of its declared type.
Note the "as if by assignment" part. This leads us to the rules for simple assignment C11 6.5.16.1, constraints. The code in the question would behind the lines be equivalent to an assignment expression such as int c = (char[]){"X"}; where the left operand is an arithmetic type and the right operand is a pointer. No such case can be found anywhere in C11 6.5.16.1.
Therefore the code is a constraint violation of 6.5.16.1.
If a compiler lib chooses to implement isalpha as a macro and thereby loses the type check ability somehow by not performing the normal lvalue conversion of function parameters during assignment, then that library might very well be non-conforming, if the compiler fails to produce a diagnostic message.
My interpretation is that although the standard requires that there is an isalpha function, in 7.1.4 it specifically allows the implementation to additionally define a macro with the same name that hides the function declaration.
This means that calling isalpha in a program (without #undef'ing it first) is allowed to result in a macro expansion to something other than the literal function call for which 6.5.2.2 would require a diagnostic.
I am using orwell dev c++ IDE. I know that in the old C89 Standard & pre standard C++ supports default to int rule when return type of function isn't explicitly specified in function definition. But it has banned in C++. But recently i wrote following simple C program and it works fine.
#include <stdio.h>
void fun();
int main(void)
{
int a=9;
printf("%d",a);
printf("%d",a);
fun();
return 0;
}
a=1;
void fun()
{
printf("%d",a);
}
Is it true that default int rule is also applied to variables? My compiler shows me following warnings.
[Warning] data definition has no type or storage class [enabled by default]
[Warning] type defaults to 'int' in declaration of 'a' [enabled by default]
Why C99 standard still allows default to int? It fails in compilation in C++. Correct me if i am wrong? This C program also works on on line compilers like ideone.com
This is explained in the C99 rationale:
A new feature of C99:
In C89, all type specifiers could be omitted from the declaration
specifiers in a declaration. In such a case int was implied. The
Committee decided that the inherent danger of this feature outweighed
its convenience, and so it was removed. The effect is to guarantee the
production of a diagnostic that will catch an additional category of
programming errors. After issuing the diagnostic, an implementation
may choose to assume an implicit int and continue to translate the program in order to support existing source code that exploits this feature.
In other words, it's officially removed from the C99 standard, but compilers may still choose to follow this behavior and issue a diagnostic, as GCC does. For example, view their warning options page for -Wimplicit-int. To make these warnings compile as errors, use -pedantic-errors or -Werror.
As per #Anonymous's answer, c++98 contains a similar rule about type specifiers.
7.1.5/2
At least one type-specifier that is not a cv-qualifier is required
in a declaration unless it declares a constructor, destructor or
conversion function.80)
80) There is no special provision for a
decl-specifier-seq that lacks a type-specifier or that has a type-specifier that only specifies cv-qualifiers. The "implicit int" rule of C is no longer supported.
For example, GCC supports ISO/IEC 14882:1998 and above, so this would be an error no matter what.
The C99 standard does not allow types to be omitted.
Section 6.7.2.2 says:
At least one type specifier shall be given in the declaration
specifiers in each declaration, and in the specifier-qualifier list in
each struct declaration and type name.
I was writing some C code, and noticed what I thought to be an error, but was not. I had the following type declaration statement.
const fee;
However, it was uncaught initially because the compiler and I didn't catch it. So I was curious as to why C allows this and what is the default type.
Only the original version of C language standard (ANSI/ISO C89/90) allows this. Such variable declaration defaults to type int in accordance with "implicit int" rule. That rule was present in C since the beginning of time. That's just how the language was originally defined.
Note that the declaration-specifiers portion of a declaration cannot be omitted completely, e.g. a mere
fee;
does not declare an int variable. It is illegal even in the original C. But once you add some sort of declaration specifier or qualifier, the declaration becomes legal and defaults to int type, as in
static fee;
const fee;
register fee;
However, all this is illegal in C99 and in later versions of language, since these versions of language specification outlawed "implicit int".
If "a function" were compiled separately, the mismatch would not be detected, "the function" would return a double that main would treat as an int... In the light of what we have said about how declarations must match definitions this might seems surprising. The reason a mismatch can happen is that if there is no function prototype, a function is implicitly declared by its first appearance in an expression, such as
sum += "the function"(line);
If a name that has not been previously declared occurs in an expression and is followed by a left parenthesis, it is declared by context to be a function name, the function is assumed to return an int, and nothing is assumed about its arguments.
I apologize beforehand for the ambiguous question, but what does this mean?
By the way this is page 73 chapter 4.3 from Brian W. Kernighan and Dennis M. Ritchie's C Programming Language book, 2nd edition.
K&R2 covers the 1989/1990 version of the language. The current ISO C standard, published in 1999 2011, drops the "implicit int" rule, and requires a visible declaration for any function you call. Compilers don't necessarily enforce this by default, but you should be able to request more stringent warnings -- and you definitely should. In well-written new code, the rule is irrelevant (but it is necessary to understand it).
An example: the standard sqrt() function is declared in <math.h>:
double sqrt(double);
If you write a call without the required #include <math.h>:
double x = 64.0;
double y = sqrt(x);
a C90 compiler will assume that sqrt returns int -- and it will generate code to convert the result from int to double. The result will be garbage, or perhaps a crash.
(You could manually declare sqrt yourself, but that's the wrong solution.)
So don't do that. Always include whatever header is required for any function you call. You might get away with calling an undeclared function if it does return int (and if your compiler doesn't enforce strict C99 or C11 semantics, and if a few other conditions are satisfied), but there's no good reason to do so.
Understanding the "implicit int" rule is still useful for understanding the behavior of old or poorly written code, but you should never depend on it in new code.
Function prototypes were introduced into the language late.
Before prototypes, the compiler would assume that every argument passed to every unknown function should be passed as an integer and would assume that the return value was also an integer.
This worked fine for the few cases where it was correct, but meant people had to write programs in an awkward order so that functions would never rely on unknown functions that did not match this expectation.
When prototypes were introduced into C89 (aka ANSI C or ISO C), the prototypes allow the compiler to know exactly what types of arguments are expected and what types of results will be returned.
It is strongly recommended that you use function prototypes for all new code; when working on an entirely old code base, the prototypes might be harmful. (Or, if the code must be compilable on a pre-ANSI C compiler, then you might wish to leave off the prototypes so it can be built on the ancient software. gcc is the only place I've seen this in a long time.)
It's just stating that if the compiler comes across code that calls an unknown function, then it implicitly treats it as if it had already seen a declared prototype of the form int unknown();