I have the following program
main()
{
char a,b;
printf("will i get the job:");
scanf("%c",&a);
printf("%c",a);
printf("We did it");
}
I saved the file as Hope.c. When I try to compile the code above with the gcc compiler, I will get the following error:
Hope.c:In function 'main':
Hope.c:4:2:warning:incompatible implicit declaration of built-in function 'printf' [enabled by default]
Hope.c:5:2:warning:incompatible implicit declaration of built-in function scanf[enabled by default]
The compiler gives this error when I use printf() or scanf(), even in a simple "Hello world" program.
Is there something wrong with my code, or is there a problem with the compiler?
You're missing #include <stdio.h> at the top. Note that these were warnings, though, not errors. Your program should still have compiled as is.
Also, for good measure, you should write out the return type and parameters to main() and return a value at the end.
#include <stdio.h>
int main(void)
{
char a,b;
printf("will i get the job:");
scanf("%c",&a);
printf("%c",a);
printf("We did it");
return 0;
}
When you call functions that you're not familiar with, look at the man page and include the headers that are mentioned there. It's #include <stdio.h> in your case.
That's really extermely important, e.g. I have experienced printf( "%s", func( ) ) causing a segmentation fault although func() returned a valid null terminated string, but there was no prototype that declared the return type of func() as char * (doing a little bit research, we found that only the last four bytes of the 64 bit pointer have been passed to printf())
Yes, there's something wrong with the code. You're using the functions printf and scanf without declaring them.
The usual thing to do is use the declarations shipped with the compiler (because they're known to be correct) with
#include <stdio.h>
C.89/C.90 permits implicit declarations of functions. Your warning messages are informing you that you have not provided explicit declarations for scanf and printf. As has been mentioned, you can correct this by adding #include <stdio.h> to the beginning of your program. By not doing so, the behavior of your program is undefined.
Because scanf() and printf() have implicit declarations, they are treated as if their prototypes were given as:
extern int scanf ();
extern int printf ();
These declarations state that scanf() and printf() take an as of yet unknown number of arguments and return and int. However, this kind of declaration still assumes that these functions will take a fixed number of arguments. This is incompatible with their true prototypes, in which they take a variable number of arguments:
extern int scanf (const char *, ...);
extern int printf (const char *, ...);
Your C compiler apparently knows about the true prototypes of these functions because it treats those functions as "built-ins", meaning it can generate special case code when compiling to source code that calls those functions. Since the implicit declaration does not match its built-in knowledge of their prototypes, it generated the warning.
A compiler that did not have this "built-in knowledge" probably would not have generated the warning. It would then have generated code to call scanf() and printf() as if they took a fixed number of arguments. The error then may occur at runtime, since the calling convention for a function that takes a variable number of arguments may differ from the calling convention of a function that takes a fixed number of arguments.
This is all described in C.89 §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.
...
If the expression that denotes the called function has a type that
does not include a prototype, the integral promotions are performed on
each argument and arguments that have type float are promoted to
double. ... If the function is defined with
a type that includes a prototype, and the types of the arguments after
promotion are not compatible with the types of the parameters, or if
the prototype ends with an ellipsis ( ", ..." ), the behavior is
undefined.
Note that C.99 removes the allowance for implicit function declarations.
Related
I tried this program on DevC++ that would call two different types of function, one returning int and one returning char. I'm confused why the int function doesn't need a prototype, while the char one and any other type of function does.
#include <stdio.h>
//int function1();
char function2() ;
int main (){
int X = function1() ;
char Y = function2() ;
printf("%d", X) ;
printf ("%c", Y) ;
return 0 ;
}
int function1(){
return 100 ;
}
char function2(){
return 'B' ;
}
The output:
100B
If I remove the prototype for the char function, it results in:
[Error] conflicting types for 'function2'
[Note] previous implicit declaration of 'function2' was here
In the old days of C any function that was not declared explicitely was supposed to return int type when you call it.
If the compiler then finds the function implementation and sees an int return type, everything is fine.
If the function returns anything else than int you get the error message as you saw with the second function.
This implicit int type declaration was removed from the standard with C99. Now you should at least get a warning from your compiler when you use a function without prototype.
If you did not get any diagnostic message for first funcion, you should turn up warning level in your compiler or switch to at least C99 mode instead of ancient versions.
Edit:
Empty parameter lists in funcion definitions is a deprecated feature as well.
You should not use it.
Always provide prototype for every function with return type and parameter list.
If a function is used before it is declared, the usage becomes an implicit declaration of the function. When a function f is implicitly defined, the definition given to it is int f(), i.e. a function which accepts an unspecified number of arguments and returns an int.
This implicit definition of a function matches the actual definition of function1 but not function2. So calling function1 this way gives no error but attempting to call function2 this way results in the implicit definition not matching the actual definition, giving an error.
This behavior goes back to pre-standardized versions of C where all objects (and a function's return type) had a default type of int if not declared. This was still present in the C89 standard but removed in the C99 standard, although some compilers such as gcc still support this obsolescent usage as an extension.
It's just an ancient relic from when C was first designed. It was actually removed as early as C99, but many compilers still support this type of declaration. But it's not recommended to use it.
I'm not sure if there were any real rationale behind it, but C was heavily inspired by the language B. And in B you did not have to specify the return type for functions. That actually made perfect sense, because there was only one type, word.
In the same way you did not have to specify the type of variables either. You only specified if it had automatic or static storage. And that's where the completely useless keyword auto in C comes from. It does not mean the same as in C++. It just means "not static".
I have noticed some behavior in C that I do not quite understand. If I define a function with an argument that I do not specify a type for and call it without any argument, the code compiles but gives a warning that the type of the parameter defaults to int.
void f(i) {
printf("%d", i);
}
int main(void) {
f();
}
If I run this on godbolt, I get the expected compiler warning, and execution prints 1 to stdout.
However, if I define the same method, but explicitly declare the argument as an int, the compiler throws an error for the function being called with too few arguments.
void f(int i) {
printf("%d", i);
}
int main(void) {
f();
}
Compiling this on godbolt produces error: too few arguments to function 'f'.
This behavior is consistent across all modern versions of gcc and clang. Why does specifying the type of the argument make this a compiler error? Also, is the behavior of the first example defined? The fact that gcc and clang both always make i 1 would make me think that this is intentional. If so, why?
The second piece of code is relatively simple. The function is defined to accept one argument, and the function call in main passed no arguments. That's a clear error.
The first piece of code is more interesting. This goes back to old style function definitions where the parameter list contains only the names of the parameters and the types appear between the closing parenthesis terminating the argument list and the opening brace before the start of the function body. Such a function properly defined would look like this:
void f(i)
int i;
{
printf("%d", i);
}
This style of specifying function arguments dates back to the original K&R C but is considered deprecated now. This variant of C also had the property that the type of a variable could be omitted in which cast it defaults to int.
However, even if you do specify the type after the argument list as in the above example, it's still not an error. So why is this?
The key parts comes from section 6.5.2.2 of the C standard regarding function calls:
2 If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.
...
8 No other conversions are performed implicitly; in particular, the number and types of arguments are not compared with those of the parameters in a function definition that does not include a function prototype declarator.
And section 6.9.1p7 regarding function definitions:
The declarator in a function definition specifies the name of the function being defined and the identifiers of its parameters. If the declarator includes a parameter type list, the list also specifies the types of all the parameters; such a declarator also serves as a function prototype for later calls to the same function in the same translation unit. If the declarator includes an identifier list, the types of the parameters shall be declared in a following declaration list. In either case, the type of each parameter is adjusted as described in 6.7.6.3 for a parameter type list; the resulting type shall be a complete object type
In the case of a K&R style function definition, the parameters are specified as an identifier list as opposed to a parameter type list. This means that the function definition does not also specify a function prototype, meaning the number and types of the parameters are not checked when the function is called.
There are two types of function prototypes:
The original, known as "K&R" [from Kernighan & Ritchie, the creators of C].
The modern, known as "ANSI" [from the ANSI standardization committee].
At first, we only had K&R:
#include <stdio.h>
void
f(i)
int i;
{
printf("%d\n",i);
}
int
main(void)
{
f();
return 0;
}
When the C language was standardized, an alternate form of function prototype was added:
#include <stdio.h>
void
f(int i)
{
printf("%d\n",i);
}
int
main(void)
{
f();
return 0;
}
These are how the functions are defined. But, if we put f in a separate file, we'd be left with the prototype declarations:
Here is K&R:
#include <stdio.h>
void f();
int
main(void)
{
f();
return 0;
}
Here is ANSI:
#include <stdio.h>
void f(int i);
int
main(void)
{
f();
return 0;
}
If you look closely at the K&R prototype, there is no way to discern the type for i.
That blemish was rectified with ANSI. If you look at that prototype, the type is for i is explicitly specified as int.
So, to answer your question, in your examples, the syntax without the int is a K&R style prototype/definition. When we add int, it is an ANSI prototype/definition.
K&R hasn't been widely used in new code since sometime in the 1990's (IIRC). But, the compilers understand it for backward compatibility with code written pre-ANSI.
Side note: I started programming in C in 1981, so I was using K&R for at least a decade (A lot of this post comes from [fading] memory). After I got a compiler that supported ANSI, after a few months trying out the ANSI prototypes on new code, I converted all my old code to use ANSI.
For more information ...
See: Function declaration: K&R vs ANSI
And, Alternative (K&R) C syntax for function declaration versus prototypes
This question already has answers here:
What does an empty parameter list mean? [duplicate]
(5 answers)
Accessing the parameters passed to a function with an empty parameter list in C
(2 answers)
Closed 2 years ago.
I have been reading the difference between function() and function(void) in C, and I came to know that
an empty parameter list in a function declaration indicates that the
function takes an unspecified number of parameters
So I ran this code:
#include <stdio.h>
void fun();
int main(void)
{
fun(12, 13.22, 1234567890987654321, "wow", 'c');
}
void fun()
{
printf("What happened to those arguments?");
}
I don't understand why C allows this. All the posts I've read so far related to this say things like it's bad practice to use it, it is obsolescent, etc. Also from the above code, I think the type of those arguments is also unspecified. So I just want to know the reason behind "unspecified arguments of unspecified type":
What can be done with those arguments?
Is it possible to access those arguments within the function?
The reason for supporting the notation is historical. Before the first C standard (C89/C90), you couldn't use prototypes in C; prototypes were one of the biggest and most important features of Standard C. All function declarations, therefore, were written the 'empty parentheses' style (when they were written at all; most functions that returned int were not declared at all). The type void was also added in C89/C90, though some compilers supported it before the standard was finalized.
Because it was crucial to the success of C89/C90 that existing code should mostly continue to work, the empty parentheses style had to be allowed by the standard. So, your code might have been written in pre-standard C as:
#include <stdio.h>
int fun(); /* This declaration would probably have been absent */
int main(void)
{
fun(12, 13.22, 1234567, "wow", 'c');
return 0; /* This was required until C99 to give reliable exit status */
}
fun(i, d, l, s, c) /* No return type - implicitly returns int */
long l; /* Defined out of sequence - bad style, but legal */
char c; /* Passed as int; converted to char in function */
char *s; /* Should define all pointer arguments */
double d; /* No definition of i; it was an int by default */
{
printf("This is what happened to those arguments:\n");
printf("i = %d\n", i);
printf("d = %f\n", d);
printf("l = %ld\n", l);
printf("s = [%s]\n", s);
printf("c = %c\n", c);
/* No return statement - don't use the value from the function */
}
For the curious: you could omit the char *s; line in the function definition, and it still compiled and produced the same output. It was a bad idea to try that, though. You could replace the line int fun(); with static fun(); and the code compiles cleanly when no diagnostics are requested.
You get no warnings even now if you compile this file (old31.c) with GCC 9.3.0 using:
$ gcc -std=c90 -o old31 old31.c
$
Your example as written is skirting around the backwards compatibility provisions. Using void means it was new code (it would not have been valid in many pre-standard C compilers because it used void). And new code should not exploit the backwards-compatibility provisions without a good reason. That was true in 1991 as well as in the current millennium (but in 1991, there were a lot more good reasons to exploit the backwards-compatibility provisions). Good pre-standard code usually listed all parameters in the order they were used. Omitted definitions and out of sequence definitions were not entirely satisfactory.
You asked:
What can be done with those arguments?
In the code in the question, nothing can be done with the arguments. The caller pushes the values onto the stack, and pops them off when the function returns. The called function is unaware of their existence and can do nothing with them.
Is it possible to access those arguments within the function?
No — not using any standard mechanism.
There is a difference between a function declaration and a function definition when there is an empty parameter list.
Section 6.7.6.3p14 of the C standard states:
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.
What this means is that this declaration:
void fun();
Means fun takes an unknown number of parameters. While this definition:
void fun()
{
printf("What happened to those arguments?");
}
Means that fun takes no parameters. So this function call:
fun(12, 13.22, 1234567890987654321, "wow", 'c');
Is invalid and invoked undefined behavior because the number of parameters in the call don't match the actual number of parameters. This is spelled out in section 6.5.2.2p6 regarding the function call operator ():
If the expression that denotes the called function has a
type that does not include a prototype, the integer promotions
are performed on each argument, and arguments that have
type float are promoted to double. These are called the default
argument promotions. If the number of arguments does not equal
the number of parameters, the behavior is undefined. If the
function is defined with a type that includes a prototype, and either
the prototype ends with an ellipsis (, ...) or the types of
the arguments after promotion are not compatible with the types of
the parameters, the behavior is undefined.If the function is
defined with a type that does not include a prototype, and
the types of the arguments after promotion are not compatible
with those of the parameters after promotion, the behavior is
undefined, except for the following cases:
one promoted type is a signed integer type, the other promoted type is the corresponding unsigned integer type,
and the value is representable in both types;
both types are pointers to qualified or unqualified versions of a character type or void.
As for why this is allowed, it is legacy behavior that goes back to pre-standardized versions of C where the type of variables and the return type of functions defaulted to int and the method of declaring functions differed from what they are now.
I'm reading a bit of code in C, and in the variable declaration line, there's "char *p, *getenv();"
I understand "char *p" of course. What does "char *getenv()" do? Later on in the code, the function getenv() is called with a variable passed to it. But what's the point of "char *getenv();" without any arguments?
Sorry if this is basic. I'm just starting to learn C.
It is "valid C" (I would almost say "unfortunately") - but it is not particularly useful. It is a "declaration without declaration" - "I will be using a function getenv() but I'm not going to tell you what the arguments will be". It does have the advantage of preventing a compiler warning / error - something that would normally be prevented with a "real" function prototype, for example by including the appropriate .h file (in this case, stdlib.h).
To clarify: the following code
#include <stdio.h>
int main(void) {
char *p;
p = getenv("PATH");
printf("the path is %s\n", p);
return 0;
}
will throw a compiler warning (and you should never ignore compiler warnings):
nonsense.c: In function ‘main’:
nonsense.c:5: warning: implicit declaration of function ‘getenv’
nonsense.c:5: warning: assignment makes pointer from integer without a cast
Either adding #include <stdlib.h> or the line you had above, will make the warning go away (even with -Wall -pedantic compiler flags). The compiler will know what to do with the return value - and it figures out the type of the arguments on the fly because it knows the type when it sees it.
And that is the key point: until you tell the compiler the type of the return value of the function it does not know what to do (it will assume int, and make appropriate conversions for the variable you are assigning to - this can be inappropriate. For example, a pointer is often bigger than an int, so information will be lost in the conversion.)
It's a declaration (an old-style one without a prototype, since the argument list is missing) for the function getenv. Aside from being arguably bad style to hide a function declaration alongside the declaration of an object like this, it's bad to omit the prototype and bad not to be using the standard headers (stdlib.h in this case) to get the declarations of standard functions.
Here is the content of src1.c:
#include <stdio.h>
extern int w;
//int go(char); // no need to declare here. WHY????
main(){
char a='f';
go(a);
printf("%d\n", w);
}
And here is the content of src2.c:
#include <stdio.h>
int w = 99;
int go(char t){
printf("%c\n%d\n",t,sizeof(t));
}
Why isn't it mandatory to declare the go function in src1.c file after compiling it in Linux?
cc src1.c src2.c;
Does the compiler put the go function's definition from src2.c file above the main function's code so that declaration then would not be required?
In I do it this way:
#include <stdio.h>
int go(char); // need to declare here, because if not, arguments of go will be promoted to intS and they would conflict with char parameters defined in go. Error is droped!
main(){
char a='f';
go(a);
}
int go(char t){
printf("%c\n%d\n",t,sizeof(t));
}
So everyone that says, it is possible to pass whatever number and types of arguments in absence of prototype is wrong. They are promoted to ints in this case, but have to agree with those specified in definition.
I did some tests and found out that even it compiles with no errors it does not work correctly.
src1:
#include <stdio.h>
int go(int t){
printf("%d\n%d\n",t,sizeof(t));
}
sr2.c:
#include <stdio.h>
int go(int); //if I omit this prototype, program outputs 1 which is far from correct answer :)
main(){
double b=33453.834;
go(b);
}
So finally the answer could only be undefined behavior.
Thanks Maxim Skurydin
It's indeed not mandatory to have a prototype for a function before using it, but this is a quirk of the early days of C.
When there is no prototype present, the compiler cannot check the actual types that are being passed to the function or returned by it, which might be very bad in case of mismatch between the usage and declaration.
When compiler sees no prototype for go when go(b); is invoked, it assumes it has the following prototype int go(<any number of arguments can be there>). The default argument promotions are performed on the arguments prior to function invocation. Of course, if there is no function go in another translation module, you will get a linker error.
From c99 standard:
6.5.2.2 Function calls
If the expression that denotes the called function has a type that
does not include a prototype, the integer promotions are performed on
each argument, and arguments that have type float are promoted to
double. These are called the default argument promotions. If the
number of arguments does not equal the number of parameters, the
behavior is undefined. If the function is defined with a type that
includes a prototype, and either the prototype ends with an ellipsis
(, ...) or the types of the arguments after promotion are not
compatible with the types of the parameters, the behavior is
undefined. If the function is defined with a type that does not
include a prototype, and the types of the arguments after promotion
are not compatible with those of the parameters after promotion, the
behavior is undefined, except for the following cases:
— one promoted
type is a signed integer type, the other promoted type is the
corresponding unsigned integer type, and the value is representable in
both types;
— both types are pointers to qualified or unqualified
versions of a character type or void.
6.3.1.1 Boolean, characters, and integers
2/ If an int can represent all values of the original type, the value
is converted to an int; otherwise, it is converted to an unsigned int.
These are called the integer promotions.48) All other types are
update:
Does compiler put the go function's definition from src2.c file above
the main function's code so that declaration then would not be
required?
No, it doesn't put anything. A cite of the standard above says that no prototype is necessary. Each file is compiled independently so when src1.c is compiled, it doesn't know anything about src2.c and a go function definition inside.
So everyone that says, it is posible to pass whatever number and types
of arguments in absence of prototype is wrong. They are promoted to
intS in this case, but have to agree with those specified in
definition.
It is possible and I've faced a couple of obscure bugs after system-wide change that compiled just fine without any warnings for some reason (actually, it's undefined behavior).
Again, since each *.c file is compiled independently, there is now way it can check the number of arguments and their types of go function defined in another translation unit. If the function takes more arguments that you have provided, the "unused" arguments will be filled with some random data. You should keep in mind, that if arguments don't match - it's undefined behavior, which means that anything can happen.
First of all, function declarations should be put into header files. Now an answer to your question:
When you compile both the files, then at the time of linking, the linker finds the symbol definition of go() in src2.o and thus resolves the symbol reference in the executable, this is the reason why your program works.
You are trying to use sizeof() which is a compile time operator and it would thus output 1 since you are suing it on a character.
You are also passing an integer value >255 to a char variable, this would cause overflow and t would store 1789modulo255 .
When you make one executable using these two source files then final executable will have
definition of go() so no need of it.
But it's better to put declaration in a header file and then include that header file in both the source files
here is header file someheader.h
#ifndef __SMH_
#define __SMH_
int go(char);
#endif
now include it like this
#include "someheader.h"
in src1.c and src2.c
By default
go() will be int go(). i.e returns int and accepts any number of arguments. so your actual function matches with default function type.
When the compiler sees go() in str1.c it assumes that the function is defined elsewhere. It's only at the link time that the linker searches for
the definition of go().
I think, you are compiling the two files separately and link them together which is fine. Because at link time the defintion of go() exists.
If you try to compile str1.c (gcc str1.c as opposed to gcc -c str1.c)separately, you'll get the error about go() not being found by linker.
UPDATE:
Even the implicit declaration by the compiler is not standard compliant (since C99).
Technically, every function should have a prototype irrespective of its return type if it is called before compiler can see it's defintion. The implicit declaring an int returning function is no longer valid ( valid in C89) and has been removed since C99 (and C11).
Although, most compilers still issue only a warning about this, not an error. But if some compiler refuses to compile due to function prototype not being present, then you can't complain about it as it is not standard compliant.