This question already has answers here:
Implicit function declarations in C
(6 answers)
Closed 4 years ago.
I recently found a bug in software related to the following warning:
warning: implicit declaration of function ‘my_func’ [-Wimplicit-function-declaration]
Despite the warning, the code was compiling and (most of the time) working.
My question is, what happens when the code is running and that function is called? Is that undefined behaviour, or can I assume that the function call is a no-op?
This usually indicates that the header file that declares this subroutine was not #included. When a subroutine is used without having been declared, many C compilers generate an implicit declaration. This behavior is a common cause of errors, because the compiler may generate incorrect code if the implicit declaration does not match the actual definition.
This link contains a sample. It may be helpful to understand your concern.
An implicitly defined function is assumed to return int and to take an arbitrary number of arguments. That may or may not be true for the real function.
Depending on your platform, the arguments may be passed in an unexpected way, e. g. in registers, via the stack, etc. And if the way of passing the arguments doesn't match the expectations, things go crazy.
The default function declaration in C has parameters of int.
So, if you do not declare the function, the compiler will assume it returns int and has all parameters of int.
However, you still need to define the function or the linker will give an error.
Related
In C when a function is declared like void main(); trying to input an argument to it(as the first and the only argument) doesn't cause a compilation error and in order to prevent it, function can be declared like void main(void);. By the way, I think this also applies to Objective C and not to C++. With Objective C I am referring to the functions outside classes. Why is this? Thanks for reaching out. I imagine it's something like that in Fortran variables whose names start with i, j, k, l, m or n are implicitly of integer type(unless you add an implicit none).
Edit: Does Objective C allow this because of greater compatibility with C, or is it a reason similar to the reason for C having this for having this?
Note: I've kept the mistake in the question so that answers and comments wouldn't need to be changed.
Another note: As pointed out by #Steve Summit and #matt (here), Objective-C is a strict superset of C, which means that all C code is also valid Objective-C code and thus has to show this behavior regarding functions.
Because function prototypes were not a part of pre-standard C, functions could be declared only with empty parentheses:
extern double sin();
All existing code used that sort of notation. The standard would have failed had such code been made invalid, or made to mean “zero arguments”.
So, in standard C, a function declaration like that means “takes an undefined list of zero or more arguments”. The standard does specify that all functions with a variable argument list must have a prototype in scope, and the prototype will end with , ...). So, a function declared with an empty argument list is not a variadic function (whereas printf() is variadic).
Because the compiler is not told about the number and types of the arguments, it cannot complain when the function is called, regardless of the arguments in the call.
In early (pre-ANSI) C, a correct match of function arguments between a function's definition and its calls was not checked by the compiler.
I believe this was done for two reasons:
It made the compiler considerably simpler
C was always designed for separate compilation, and checking consistency across translation units (that is, across multiple source files) is a much harder problem.
So, in those early days, making sure that a function's call(s) matched its definition was the responsibility of the programmer, or of a separate program, lint.
The lax checking of function arguments also made varargs functions like printf possible.
At any rate, in the original C, when you wrote
extern int f();
, you were not saying "f is a function accepting no arguments and returning int". You were simply saying "f is a function returning int". You weren't saying anything about the arguments.
Basically, early C's type system didn't even have a way of recording the parameters expected by a function. And that was especially true when separate compilation came into play, because the linker resolved external symbols based pretty much on their names only.
C++ changed this, of course, by introducing function prototypes. In C++, when you say extern int f();, you are declaring a function that explicitly takes 0 arguments. (Also a scheme of "name mangling" was devised, which among other things let the linker do some consistency checking at link time.)
Now, this was all somewhat of a deficiency in old C, and the biggest change that ANSI C introduced was to adopt C++'s function prototype notation into C. It was slightly different, though: to maintain compatibility, in C saying extern int f(); had to be interpreted as meaning "function returning int and taking unspecified arguments". If you wanted to explicitly say that a function took no arguments, you had to (and still have to) say extern int f(void);.
There was also a new ... notation to explicitly mark a function as taking variable arguments, like printf, and the process of getting rid of "implicit int" in declarations was begun.
All in all it was a significant improvement, although there are still a few holes. In particular, there's still some responsibility placed on the programmer, namely to ensure that accurate function prototypes are always in scope, so that the compiler can check them. See also this question.
Two additional notes: You asked about Objective C, but I don't know anything about that language, so I can't address that point. And you said that for a function without a prototype, "trying to input an argument to it (as the first and the only argument) doesn't cause a compilation error", but in fact, you can pass any number or arguments to such a function, without error.
This question already has answers here:
Why is #include <stdio.h> not required to use printf()?
(3 answers)
Closed 5 years ago.
How this following code can run without including header file for printf function?
int main(){
printf("%d",1);
return 0;}
Note: This is a hand-wavy answer that will roughly be correct. Someone else who knows the gory details (for gcc, e.g.) may enlighten both of us. Here goes:
Because in C — at least for some compilers — implicitly defined functions are fine. So it compiles it, then hands it off to the linker. It sees a reference to printf, and since the linker by default links with the C runtime library, it will resolve that symbol to the correct function.
I guess an implicit function like that will get a default signature, typically expecting to return an int. As for the arguments to the function, those can't be type checked at compile time, because the compiler doesn't know what the actual function signature is. So it will just use standard calling convention, e.g. pass arguments by registers or something like that.
When you don't include and use malloc, we get implicit declaration warning.
"warning: incompatible implicit declaration of built-in function ‘malloc’"
This warning is due to fact that compiler assumes malloc defined as int malloc(size) while it is void* malloc(size).
But how does it know about void* malloc(size)? We have not included anything in header files. So how is it comparing it against something that is not included.
And after that, how does my code work? How does it find correct malloc definition and use it?
Is there any sequence order in which function definitions are scanned?
When you call a function f that has never been defined, an implicit declaration like this takes place:
int f();
Note that you can still pass arguments to f, since it was not declared int f(void); (this is for backwards compatibility with K&R C).
Thus, the compiler doesn't "know" that malloc receives a size argument, in fact you can pass it what you want, it doesn't care.
So, the mere fact that the code works is pure luck. In the case of malloc, if the code works, it just means that the size of an integer is the same size as a pointer - no more, no less - so, you can still call malloc and assign its result to a pointer, since no bits were trimmed / are missing.
The true function is found in the linking stage, after compilation takes place. By this time, your code was already compiled with a wrong function prototype. Of course, if the linker can't find the function anywhere in its path, an error is reported and everything is aborted.
For the case of malloc, and other standard library functions, there may be builtin functions to increase performance. There's even an option for gcc to disable builtin functions (-fno-builtin or -fno-builtin-function). From gcc manpage:
GCC normally generates special code to handle certain built-in
functions more efficiently; for instance, calls to "alloca" may become
single instructions that adjust the stack directly, and calls to
"memcpy" may become inline copy loops. The resulting code is often
both smaller and faster, but since the function calls no longer appear
as such, you cannot set a breakpoint on those calls, nor can you
change the behavior of the functions by linking with a different
library. In addition, when a function is recognized as a built-in
function, GCC may use information about that function to warn about
problems with calls to that function, or to generate more efficient
code, even if the resulting code still contains calls to that
function.
So, in the particular case of malloc, this is how the compiler "knows" its usual signature. Try to compile this code with gcc:
int main(void) {
char *a = malloc(12, 13, 14, 15);
return 0;
}
You will see it will abort with a compilation error:
test.c:3: error: too many arguments to function `malloc'
If you use the option -fnobuiltin, the error goes away and the warning is different:
test.c:3: warning: implicit declaration of function `malloc'
This is the same warning you get every time you use a regular function that was not previously defined, because now the compiler is ignoring what he "knows" about these functions. This example uses gcc, but other compilers will have similar behavior.
But how does it know about void* malloc(size)? We have not included anything in header files. So how is it comparing it against something that is not included.
Most modern compilers have a built-in (i. e. hard-coded in the compiler) list of common standard library functions, so the compiler knows what the declaration should be even without the function being declared (explicitly or implicitly) or called.
This does not mean that the correct declaration will be used (because the implicit declaration rule overrides the compilers apparent knowledge), but at least you know that you're doing something wrong.
The exact purpose of these built-ins is that the compiler can warn you if you forget to include a header file. (There other purposes as well, such as the opportunity to perform intrinsic optimization by knowing the semantics/implementation of a built-in function, but those do not apply here.)
The reason you got this specific warning is malloc being a built-in function in this specific compiler (as the warning states). This function receives special treatment from the compiler. The compiler has intrinsic knowledge about how this function has to be declared, so when the implicit declaration contradicts the proper declaration, the warning is issued immediately.
In general case, with ordinary (non-built-in) functions, you will get a similar waning for an implicitly declared function when the compiler actually discovers the first explicit declaration for the same function (assuming there's a mismatch between the two). In that case the warning will be issued later: not at the point of the call, but at the point of explicit declaration. That's the way it works with ordinary functions.
But with such standard (built-in) functions as malloc the compiler allows itself a bit of "cheating".
It doesn't find the correct definition if you don't declare it properly (either with an explicit declaration in your source code, or by including the proper header). It uses a default, implicit declaration for any functions that are called before they're declared. The implicit declaration includes the assumption that the function returns int.
It's then comparing the default declaration with the way that you called the function. It notices that you're assigning the result to a pointer variable rather than an integer, so it warns you that these are incompatible.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C program without header
I have been studying C for a long time . but one thing that bothering me is that , today I made a C program and forget to include the stdio.h and conio.h header files I saved the file as kc.c ? when I compiled and run this .c file the output was as I was expecting to be.
but how can a C program could run without using the standard header file?
or I am not aware with the concepts that I am missing hear?
EDIT: the program
int main()
{
int i=12,j=34;
int *pa=&i,*pb=&j;
printf("the value of i and j is %d %d respectively ",*pa,*pb);
getch();
return 0;
}
because I have used the printf() function of STDIO.H header here ,but without including it how can It got compiled and run successfully?
The compiler is allowed to make things work, but is under no obligation to do so.
You are supposed to declare all variable argument list functions before using them; not declaring printf() properly leads to undefined behaviour (and one valid undefined behaviour is to work as expected).
You should be getting warnings about the undeclared functions if you compile in C99 mode (but Turbo C probably doesn't have a C99 mode).
Nit-picking:
[H]ow can a C program could run without using the standard header file?
All programs run without using any headers whatsoever. However, most programs are compiled using the standard headers to declare the standard functions, and the better programs ensure that all functions are declared before they are used (or are defined as static functions before they are used).
C99 requires this, though many compilers will allow errant programs to compile. However, the compilation should produce a diagnostic; the diagnostic may or may not lead to the compilation failing. In practice, it usually doesn't cause the compilation to fail, but it could and with some compilers (GCC, for example) you can force the compiler's hand (e.g. with GCC's -Werror=missing-prototypes -Werror=old-style-definition options).
When the language standard being applied pre-dates ISO C99, C does not require a function to be declared or defined before it is referenced.
However when the compiler encounters such a function call, it simply assumes that the function returns an int and that it takes an indeterminate number and type of parameters. This is called am implicit declaration. If you later declare the function, or call it with a different number of parameters or incompatible parameters, you may get a warning in some compilers that the second call does not match declaration implied by the first, but the ISO C89 standard treats the function as variadic [like printf()] where any number and type of parameters are allowed.
Moreover if the actual return value is not an int, any return value accepted and processed may not make much sense one way or another.
It is bad form to rely on an implicit declaration, and most compilers would issue a warning. If your compiler did not, you need to increase the warning level; those diagnostics are there to help improve your code quality. If you simply ignored the warning (any warning for that matter), then you shouldn't!
In C++ the rules are tighter and failure to declare or define a function before referencing it is an error, since it is necessary to allow function overloading.
A header file is nothing more than a listing of constants, preprocessor macros and function prototypes. The function prototypes tell C what arguments each function takes.
If the compiler sees a function being used without a corresponding prototype or function definition, it generates an implicit declaration of the form int func(). Since C functions are linked solely by name and not by function signature (as is the case with C++), the linker later locates the function definitions in the standard library.
See I have made a library which has several .h & several .c files.
Now under some circumstances I have not removed a warning that says
warning: implicit declaration of function ‘getHandle’
Now I want to ask you, does this cause any problem in the binary of my library?
Will it negatively affect the execution of my library on embedded platforms or anywhere else?
In C90, a call to a function with no visible declaration creates an implicit declaration of a function returning int and taking the promoted types of the arguments. If your getHandle function returns a pointer, for example, then the compiler will generate code assuming that it returns an int. Assigning the result to a pointer object should at least trigger another warning. It might work ok (if int and the pointer type are the same size, and int and pointer function results are returned in the same way), or it could go badly wrong (if, for example, int is 32 bits and pointers are 64 bits, or if pointer results are returned in 68K-style address registers).
The C99 standard removed implicit int from the language. Calling a function with no visible declaration is a constraint violation, requiring a diagnostic and possibly causing your program to be rejected.
And if you just fix the problem, you don't have to waste time figuring out how and whether it will work if you don't fix it.
In such a case the compiler cannot verify that the usage of getHandle is proper - that is, whether the return value and the arguments are of the right type and count. It will just accept the way you call it without any explicit statement that this is the right way.
Adding a prototype of the function is a way to tell the compiler that this is the intended usage of the function and it will be a compile-time error not to comply to that.
It may cause some nasty bugs in case there is a mismatch between the way it's called and the way the function expects its arguments. The most likely effect will be a corruption of the stack.
If there isn't a mismatch, it won't make any difference at runtime.