I strangely found that C allows linking of function where argument list doesn't match:
//add.c
int add(int a, int b, int c) {
return a + b + c;
}
//file.c
int add (int,int); //Note: only 2 arguments
void foo() {
add(1,2);
}
I compiled add.c first, then compiled file.c, both got compiled successfully. Strangely, linker didn't give any sort of error or warning, probably the reason is C linker doesn't compare arguments while linking. I'm not 100% sure about it though. Someone please comment on this.
Now, the question is what is the good practice to avoid this situation or get some sort of warning during compilation, because in my project there are lot of functions in different files, and now & then we have to add some extra argument in the function.
Use your header files correctly.
Configure your compiler to emit as many warnings as possible.
Mind the warnings!
add.h
#ifndef ADD_H_INCLUDED
#define ADD_H_INCLUDED
int add(int a, int b, int c);
#endif
add.c
#include "add.h"
int add(int a, int b, int c) {
return a + b + c;
}
file.c
#include "add.h"
void foo() {
add(1, 2);
}
C linker doesn't compare arguments while linking.
That is correct. Unlike C++ linker which considers argument types to be part of a function signature, C linker considers only function names. That is why it is possible to create a situation with undefined behavior simply by supplying a wrong function prototype the way that you show.
what is the good practice to avoid this situation or get some sort of warning during compilation?
Always put prototypes of functions that you are intended to share into a header, and include that header from the places where the function is used and the place where the function is defined. This would ensure that compiler issues a diagnostic message. Treat all compiler warnings as errors. C compilers are often rather forgiving, so their warnings usually indicate something very important.
Calling a function with to few arguments leads to undefined behavior as the value of those arguments will be indeterminate.
Related
1 ) Why would we provide the compiler with the same information two times ?
2 ) Isn't it redundant ?
3) When should we follow this rule ?
4) When can we omit this double declaration and
definition ?
void fx(void);
void fx ( void ){
printf("Hello World\n");
}
int main(void)
{
fx();
}
1 ) Why would we provide the compiler with the same information two times ?
When C was first designed computers were extremely limited (e.g. RAM measured in KiB and not MiB or GiB, single CPU with < 1 MHz clock instead multiple CPus with > 1 GHz clock, etc). There were many tricks to cope with this (splitting "compiling" into multiple phases, splitting "programs" into multiple compilation units, reading file/s in small pieces so the whole file isn't in RAM, etc).
One of these tricks is to parse the source files in a single pass. This meant that if you do something like this:
int foo(int x) {
return bar(x);
}
int bar(int x) {
return x;
}
..the compiler wouldn't have any clue what "bar()" is while its parsing "foo()" (because it won't see "bar()" until later). The solution was declarations - allow the programmer to declare things before they're defined, so the compiler can do a single pass and not get confused by things it hadn't seen yet.
When can we omit this double declaration and definition ?
You can omit the declaration if the compiler will see the definition before that definition is used. For example, this would be fine:
int bar(int x) {
return x;
}
int foo(int x) {
return bar(x);
}
2 ) Isn't it redundant ?
It is redundant, but necessary according to the C language specs because it was necessary 50+ years ago (to make a compiler practical on "extremely resource constrained" computers); even though it hasn't made sense for 30+ years and newer languages don't require it.
In your case, it is not needed.
But in this case:
double fx(double x);
int main(void)
{
printf("%f\n", fx(4.0));
printf("%f\n", dx(4.0));
}
double fx(double x)
{
return x * x;
}
double dx(double x)
{
return x * x;
}
<source>: In function 'main':
<source>:21:20: warning: implicit declaration of function 'dx'; did you mean 'fx'? [-Wimplicit-function-declaration]
21 | printf("%f\n", dx(4.0));
| ^~
| fx
<source>: At top level:
<source>:29:8: error: conflicting types for 'dx'; have 'double(double)'
29 | double dx(double x)
| ^~
<source>:21:20: note: previous implicit declaration of 'dx' with type 'int()'
21 | printf("%f\n", dx(4.0));
https://godbolt.org/z/6ffWf9xG8
Generally, function prototypes like
double fx(double);
1 ) Why would we provide the compiler with the same information two
times ?
Tells the compiler that somewhere in the code or libraries function fx was or will be defined and it takes a double parameter and returns double. The compiler can emit the correct code to call this function, pass the parameters and use the returned value
2 ) Isn't it redundant
In your example it is. It is not if the definition of the function is not known prior to the function call.
When should we follow this rule ?
I have explained it above.
When can we omit this double declaration and definition ?
When function is defined in the same compilation unit and it is defined before the (as position in the .c file) before first call.
A function declaration without a body, like void fx(void); is called a prototype, and its purpose is to inform the compiler that there exists a function with some return type, some name, and optionally some set of parameters that it can expect to find somewhere else during compilation or afterwards when it's time to link. These are part of the language because they allow programmers to design their software modularly.
Declaring a function prototype prevents the compiler from complaining when you call a function that it has not yet seen the definition of, for instance:
#include <stdio.h>
int foo(int in); //Without this the compiler will complain and/or refuse to compile
int main(){
printf("%d\n",foo(7));
}
int foo(int in){
return in + 1;
}
Additionally the first line of the example above says #include <stdio.h> which tells the compiler to include the C-standard io header file. stdio.h contains a prototype of printf which tells it that it will be able to find a function in the form int printf(const char*,...); once it is time to link the program.
Alternatively, you can write separate files "foo.c", "foo.h" and "main.c" for a more modular approach, like so:
main.c
#include <stdio.h>
#include "foo.h" //Include .h file to get prototype
int main(){
printf("%d\n",foo(7));
}
foo.h
#ifndef FOO_H
#define FOO_H
int foo(int in); //Prototype of foo()
#endif
foo.c
#include "foo.h"
int foo(int in){ //Declatation of foo()
return in + 1;
}
Then you can compile foo.c into an object file and pass it to the compiler along with main.c like so:
gcc -c foo.c
gcc -o main main.c foo.o
You are not forced to use prototypes if you do not want to, but if you choose not to use them you will be required to declare every function in your program before it is called in another.
Files: A(main), B
I have learned that B's function can't be use in A without
funcntion definitions.
But my code ran normally with A, B files without function definitions
This is my code:
B.c
void a()
{
printf("hi");
}
A.c
#include <stdio.h>
void main()
{
a();
}
What is it? I'm confused.
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
addendum...
sorry for my bad question.
my code works well with error.
but i couldn't see error.
but i have more question for difference between
'void a();'
'extern void a();'
Once upon a time, C did not require prior declaration of all functions. Many compilers still let you get away with this.
In file A.c, when you called
a();
where a was a function the compiler has never seen before, the compiler assumed that the declaration
extern int a();
was in scope. That is, the compiler assumed that a was a function taking unspecified arguments and returning int.
Or, that used to be the rule. That rule is no longer in C, so yes, you are supposed to explicitly declare all your functions before you call them. Most of today's compilers will warn you when they apply the old rule, and many aren't willing to apply the rule at all, or at least, not unless you use a non-default option flag requesting them to. But it sounds like your compiler is still willing to apply the rule without warning or error. That's great if you're compiling a bunch of very old code, but it's not so great if you're trying to learn modern C.
Now, in this case you have the additional problem that the actual definition of function a in file B.c defines it as returning void, not int, so theoretically that's wrong, too. But, in practice, the error of misdeclaring (or mis-calling) void- versus int-returning functions is an innocuous one, that doesn't cause any real problems. (It's still wrong, though, and worth avoiding.)
I think you know this, but a correct setup would either be to have file A.c look like this:
#include <stdio.h>
extern void a(void);
int main()
{
a();
}
or else to create the file B.h containing
extern void a(void);
and then to have file A.c look like this:
#include <stdio.h>
#include "B.h"
int main()
{
a();
}
(Note that I have also changed void main() to int main(), for correctness. If you're using an old compiler, as it sounds like you are, you may also have to add the line return 0; at the end of main().)
Addendum. You had also asked about that extern keyword. It has to do with the distinction between declarations and definitions. But this distinction plays out slightly differently for functions, versus global variables.
Declarations explain what type something has. Definitions explain what type something has, and they additionally allocate memory for the something, and supply its initial value.
These are declarations:
extern int i;
int f(int);
extern int f2(int, double);
These are definitions:
int i;
int i2 = 2;
int f(int x) { return 2 * x; }
int f2(int n, double x) { return n * x; }
The keyword extern explicitly says, "This is a declaration, the definition is somewhere else." For global variables, this makes a big difference. But for functions, when you say int f(int);, the compiler can tell, when it finds a , instead of a {, that this is a declaration (not a definition), so the keyword extern is optional in function declarations.
(Also, functions are always global in C; there are no local functions.)
See also section 4.2 and section 4.3 of these course notes.
This question already has answers here:
Must declare function prototype in C? [duplicate]
(10 answers)
Closed 7 years ago.
I have two source files test1.c and test2.c.
In test1.c:
#include <stdio.h>
void main() {
checks(); }
In test2.c:
#include <stdio.h>
void checks(){
printf("This is a sample Text");
}
In this case I can successfully build and run this program.
So why should I use:
void checks();
To declare the function?
It seems perfectly fine now.
I am Using C99.
In your case, the check() function has a very simple prototype and the default prototype applied by the C compiler is to accept anything as argument and to return an int. It is probably what is done here (except that, as you do not store the result of the function it is optimized out without noticing it).
If you want to check my theory, try to write this (and it should work until it reaches the linking phase):
int result = check();
At the end, your code work because the linker finally find something that work to plug for the check() function (yet, it should still expect an int at some point).
In fact, the declaration of a function prototype is only useful in two cases:
The code of the function and the use of the function are in the same file.
When you use the function before its declaration (code source), then you need to tell the compiler what to expect when trying to statically type the function you are writing (the compiler read a source code file from top to bottom).
For example:
int bar (int a, int b, bool c);
int foo (int a, bool b) {
int result = bar (a, a, c);
...
}
int bar (int a, int b, bool c) {
...
}
The code of the function the use of the function are not in the same file.
Then, you usually get the definition of the function through a header file which collect all the information needed by the compiler to know how to statically type your code. The header file (*.h) contains all the prototypes of the functions of the module you are using. The implementation of the functions will come after at linking time.
Note that, I usually try to avoid the first case because it is really not logical. When you read a source code, you go from top to bottom, just as the compiler do, and you expect to find the function definition before its usage... So, it is much more logical to structure your code in a way that do not need to require such artifacts. In my humble opinion...
The following test.c program
int main() {
dummySum(1, 2);
return 0;
}
int dummySum(int a, int b) {
return a + b;
}
...doesn't generate any warning when compiled with gcc -o test test.c, whereas the following one does:
int main() {
dummySum(1, 2);
return 0;
}
void dummySum(int a, int b) {
a + b;
}
Why?
When faced with an undeclared function, the compiler assumes a function that accepts the given number of arguments (I think) and returns int (that part I'm sure of). Your second one doesn't, and so you get the redefinition warning.
I believe, based on a very quick scan of the foreward, that C99 (PDF link) removed this. No great surprise that GCC still allows them (with a warning), though; I can't imagine how much code would start failing to compile...
Recommend using -Wall (turning on all warnings) so you get a huge amount of additional information (you can turn off specific warnings when you have a really good reason for whatever you're doing that generates them if need be).
A function cannot be used before it has been declared. When a function declaration is not visible, the implementation assumes in C89 that the function:
takes an unspecified (but fixed) number of parameters
returns an int
This is called an implicit function declaration.
In C99, implicit declarations of function have been removed of the language and the implementation is free to refuse to translate the source code.
I discovered something strange in gcc and hoping to get some input whether its a feature or quirk.
Essentially I have a function defined in func.c as
void f(int a, int b, FILE* f)
{
...
...
}
There is no corresponding header file. But gcc doesn't give any warning when I call f(a,b) and gdb shows me that f is called with three parameters?
Why is this the case?. What is the semantics for filling up the third argument.
If f() doesn't have a declaration anywhere and is not defined in the current compilation unit, the compiler assumes that f() returns int and can take any number of arguments.
I know this is odd, but in the old days this was possibly a way to reduce the number of header files that have to be included, and hence faster compilation.