Inconsistent declaration and definition in C [duplicate] - c

This question already has answers here:
C function with no parameters behavior
(2 answers)
Closed 8 years ago.
Today I have spend considerable time finding a "bug" that can be demonstrated by this simple code:
main.c
#include "func.h"
#include <stdio.h>
void main(){printf("func: %f", getX());}
func.c
#include "func.h"
static float x[2] = {1.0f, 2.0f};
float getX(int n){return x[n];}
func.h
float getX();
and it compiles & links (VS2010 with /W3) without any warning.
Sample output from the run is
func: 1.000000
Can someone explain me how it can work if function declaration and definition do not match and why it is not worth to output any warning?
Thanks

In C:
float getX();
is not the same as:
float getX(void);
In the first case you are specifying a function that returns float but takes unspecified parameters - in the second case you are specifying a function which returns float but which takes no parameters.
So a definition of the form float getX(int n) is compatible with the first case, but not the second, which explains why you do not seen an error/warning.
If you change to the correct prototype (the second version) then you should see the required error/warning.
Note that this is different behaviour than for C++, where the two forms are equivalent.
As for the output you are seeing when you run the program, this is just a random consequence of undefined behaviour - literally anything could happen if you call a function with incorrect parameters.
Take home message: in C you should always use the second form when declaring a prototype that takes no parameters - unfortunately you'll find that it's very common for people to omit the void (probably because of bad habits acquired from writing C++ code, or just because it requires fewer keystrokes).

This declaration means that getX accepts any number of parameters:
float getX();
To declare a function that takes no parameters, use:
float getX(void); // This will result in a compiler error for func.c

Related

When the declaration of the function is in a traditional style, why isn't the output correct?

I have declared the function pow in the traditional way of declaration in C. However, the output of function is incorrect. I don't need to include math.h here as I am declaring the function and the object code for it is already present. Here is my code:
#include<stdio.h>
double pow(); //traditional declaration doesnt work, why??
int main()
{
printf("pow(2, 3) = %g", pow(2, 3));
return 0;
}
The output for the above is 1 whereas it should be 8. Please help me with it.
traditional declaration doesnt work, why??
Because without a prototype, those two ints you provided don't get converted to the doubles that pow actually accepts. With "traditional" declarations you must painstakingly make sure you provided exactly the type of arguments expected by the function, or you'll have yourself undefined behavior in your program.
This is one reason to favor prototypes, and to actually use the standard library headers that provide them for standard functions.

Why should I declare a function in C? [duplicate]

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...

C function definition and declaration matching in different files [duplicate]

With the following code:
int main(){
printf("%f\n",multiply(2));
return 0;
}
float multiply(float n){
return n * 2;
}
When I try to compile I get one warning: "'%f' expects 'double', but argument has type 'int'" and two errors: "conflicting types for 'multiply'", "previous implicit declaration of 'multiply' was here."
Question 1: I am guessing that it's because, given the compiler has no knowledge of function 'multiply' when he comes across it the first time, he will invent a prototype, and invented prototypes always assume 'int' is both returned and taken as parameter. So the invented prototype would be "int multiply(int)", and hence the errors. Is this correct?
Now, the previous code won't even compile. However, if I break the code in two files like this:
#file1.c
int main(){
printf("%f\n",multiply(2));
return 0;
}
#file2.c
float multiply(float n){
return n * 2;
}
and execute "gcc file1.c file2.c -o file" it will still give one warning (that printf is expecting double but is getting int) but the errors won't show up anymore and it will compile.
Question 2: How come when I break the code into 2 files it compiles?
Question 3: Once I run the program above (the version split into 2 files) the result is that 0.0000 is printed on the screen. How come? I am guessing the compiler again invented a prototype that doesn't match the function, but why is 0 printed? And if I change the printf("%f") to printf("%d") it prints a 1. Again, any explanation of what's going on behind the scenes?
Thanks a lot in advance.
So the invented prototype would be "int multiply(int)", and hence the errors. Is this correct?
Absolutely. This is done for backward compatibility with pre-ANSI C that lacked function prototypes, and everything declared without a type was implicitly int. The compiler compiles your main, creates an implicit definition of int multiply(int), but when it finds the real definition, it discovers the lie, and tells you about it.
How come when I break the code into 2 files it compiles?
The compiler never discovers the lie about the prototype, because it compiles one file at a time: it assumes that multiply takes an int, and returns an int in your main, and does not find any contradictions in multiply.c. Running this program produces undefined behavior, though.
Once I run the program above (the version split into 2 files) the result is that 0.0000 is printed on the screen.
That's the result of undefined behavior described above. The program will compile and link, but because the compiler thinks that multiply takes an int, it would never convert 2 to 2.0F, and multiply will never find out. Similarly, the incorrect value computed by doubling an int reinterpreted as a float inside your multiply function will be treated as an int again.
An unspecified function has a return type of int (that's why you get the warning, the compiler thinks it returns an integer) and an unknown number of unspecified arguments.
If you break up your project in multiple files, just declare a function prototype before you call the functions from the other files, and all will work fine.
Question1:
So the invented prototype would be "int multiply(int)", and hence the
errors. Is this correct?
Not exactelly yes because it it depends of your Cx (C89, C90, C99,...)
for function return values, prior to C99 it was explicitly specified that if no function declaration was visible the translator provided one. These implicit declarations defaulted to a return type of int
Justification from C Standard (6.2.5 page 506)
Prior to C90 there were no function prototypes. Developers expected to
be able to interchange argu-ments that had signed and unsigned
versions of the same integer type. Having to cast an argument, if the
parameter type in the function definition had a different signedness,
was seen as counter to C’s easy-going type-checking system and a
little intrusive. The introduction of prototypes did not completely do
away with the issue of interchangeability of arguments. The ellipsis
notation specifies that nothing is known about the 1590 ellipsis
supplies no information expected type of arguments. Similarly, for
function return values, prior to C99 it was explicitly specified that
if no function declaration was visible the translator provided one.
These implicit declarations defaulted to a return type of int . If the
actual function happened to return the type unsigned int , such a
default declaration might have returned an unexpected result. A lot of
developers had a casual attitude toward function declarations. The
rest of us have to live with the consequences of the Committee not
wanting to break all the source code they wrote. The
interchangeability of function return values is now a moot point,
because C99 requires that a function declaration be visible at the
point of call (a default declaration is no longer provided)
Question 2:
How come when I break the code into 2 files it compiles?
it will compile and it will be treated like indicated in the first question exactelly the same
Question 1: Yes you are correct. If there is no function prototype, the default type is int
Question 2: When you are compiling this code as one file, the compiler see that there is already function named multiply and it has a different type than supposed (double instead of int). Thus compilation doesn't work.
When you separate this in two files, the compiler makes two .o files. In the first one it suppose that the multiply() function will be in other file. Then linker links both files into a binary and according to the name multiply inserts call of float multiply() on the place of int multiply() supposed by the compiler in the first .o file.
Question 3: If you read int 2 as a float, you will get a very small number (~1/2^25), so after that you multiply it by 2 and it still remains too small for format %f. That's why you see 0.00000.

Questions about C Function Prototypes and Compilation

With the following code:
int main(){
printf("%f\n",multiply(2));
return 0;
}
float multiply(float n){
return n * 2;
}
When I try to compile I get one warning: "'%f' expects 'double', but argument has type 'int'" and two errors: "conflicting types for 'multiply'", "previous implicit declaration of 'multiply' was here."
Question 1: I am guessing that it's because, given the compiler has no knowledge of function 'multiply' when he comes across it the first time, he will invent a prototype, and invented prototypes always assume 'int' is both returned and taken as parameter. So the invented prototype would be "int multiply(int)", and hence the errors. Is this correct?
Now, the previous code won't even compile. However, if I break the code in two files like this:
#file1.c
int main(){
printf("%f\n",multiply(2));
return 0;
}
#file2.c
float multiply(float n){
return n * 2;
}
and execute "gcc file1.c file2.c -o file" it will still give one warning (that printf is expecting double but is getting int) but the errors won't show up anymore and it will compile.
Question 2: How come when I break the code into 2 files it compiles?
Question 3: Once I run the program above (the version split into 2 files) the result is that 0.0000 is printed on the screen. How come? I am guessing the compiler again invented a prototype that doesn't match the function, but why is 0 printed? And if I change the printf("%f") to printf("%d") it prints a 1. Again, any explanation of what's going on behind the scenes?
Thanks a lot in advance.
So the invented prototype would be "int multiply(int)", and hence the errors. Is this correct?
Absolutely. This is done for backward compatibility with pre-ANSI C that lacked function prototypes, and everything declared without a type was implicitly int. The compiler compiles your main, creates an implicit definition of int multiply(int), but when it finds the real definition, it discovers the lie, and tells you about it.
How come when I break the code into 2 files it compiles?
The compiler never discovers the lie about the prototype, because it compiles one file at a time: it assumes that multiply takes an int, and returns an int in your main, and does not find any contradictions in multiply.c. Running this program produces undefined behavior, though.
Once I run the program above (the version split into 2 files) the result is that 0.0000 is printed on the screen.
That's the result of undefined behavior described above. The program will compile and link, but because the compiler thinks that multiply takes an int, it would never convert 2 to 2.0F, and multiply will never find out. Similarly, the incorrect value computed by doubling an int reinterpreted as a float inside your multiply function will be treated as an int again.
An unspecified function has a return type of int (that's why you get the warning, the compiler thinks it returns an integer) and an unknown number of unspecified arguments.
If you break up your project in multiple files, just declare a function prototype before you call the functions from the other files, and all will work fine.
Question1:
So the invented prototype would be "int multiply(int)", and hence the
errors. Is this correct?
Not exactelly yes because it it depends of your Cx (C89, C90, C99,...)
for function return values, prior to C99 it was explicitly specified that if no function declaration was visible the translator provided one. These implicit declarations defaulted to a return type of int
Justification from C Standard (6.2.5 page 506)
Prior to C90 there were no function prototypes. Developers expected to
be able to interchange argu-ments that had signed and unsigned
versions of the same integer type. Having to cast an argument, if the
parameter type in the function definition had a different signedness,
was seen as counter to C’s easy-going type-checking system and a
little intrusive. The introduction of prototypes did not completely do
away with the issue of interchangeability of arguments. The ellipsis
notation specifies that nothing is known about the 1590 ellipsis
supplies no information expected type of arguments. Similarly, for
function return values, prior to C99 it was explicitly specified that
if no function declaration was visible the translator provided one.
These implicit declarations defaulted to a return type of int . If the
actual function happened to return the type unsigned int , such a
default declaration might have returned an unexpected result. A lot of
developers had a casual attitude toward function declarations. The
rest of us have to live with the consequences of the Committee not
wanting to break all the source code they wrote. The
interchangeability of function return values is now a moot point,
because C99 requires that a function declaration be visible at the
point of call (a default declaration is no longer provided)
Question 2:
How come when I break the code into 2 files it compiles?
it will compile and it will be treated like indicated in the first question exactelly the same
Question 1: Yes you are correct. If there is no function prototype, the default type is int
Question 2: When you are compiling this code as one file, the compiler see that there is already function named multiply and it has a different type than supposed (double instead of int). Thus compilation doesn't work.
When you separate this in two files, the compiler makes two .o files. In the first one it suppose that the multiply() function will be in other file. Then linker links both files into a binary and according to the name multiply inserts call of float multiply() on the place of int multiply() supposed by the compiler in the first .o file.
Question 3: If you read int 2 as a float, you will get a very small number (~1/2^25), so after that you multiply it by 2 and it still remains too small for format %f. That's why you see 0.00000.

Please explain How prog works

#include<stdio.h>
int f();
int main()
{
f(1);
f(1,2);
f(1,2,3);
}
f(int i,int j,int k)
{
printf("%d %d %d",i,j,k);
}
it is running fine(without any error) ...can u plz explain how it executes ?
how f(1) and f(1,2) links to f(int,int,int) ?
You must have a different definition of "error" to me :-) What gets printed the first two times you call your f function? I get
1 -1216175936 134513787
1 2 134513787
1 2 3
for my three function calls.
What you're seeing is a holdover from the very early days of C when people played footloose and fancy-free with their function calls.
All that is happening is that you are calling a function f and it's printing out three values from the stack (yes, even when you only give it one or two). What happens when you don't provide enough is that your program will most likely just use what was there anyway, usually leading to data issues when reading and catastrophic failure when writing.
This is perfectly compilable, though very unwise, C. And I mean that in a very real, "undefined behaviour", sense of the word (referring specifically to C99: "If the expression that denotes the called function has a type that does not include a prototype, ... if the number of arguments does not equal the number of parameters, the behaviour is undefined").
You should really provide fully formed function prototypes such as:
void f(int,int,int);
to ensure your compiler picks up this problem, and use ellipses (...) in variable parameter functions.
As an aside, what usually happens under the covers is that the calling function starts with a stack like:
12345678
11111111
and pushes (for example) two values onto a stack, so that it ends up like:
12345678
11111111
2
1
When the called function uses the first three values on the stack (since that's what it wants), it finds that it has 1, 2 and 11111111.
It does what it has to do then returns and the calling function clears those two values off the stack (this is called a caller-makes-good strategy). Woe betide anyone who tries this with a callee-makes-good strategy :-) although that's pretty unusual in C since it makes variable argument functions like printf a little hard to do.
This declaration:
int f();
...tells the compiler "f is a function that takes some fixed number of arguments, and returns int". You then try to call it with one, two and three arguments - C compilers are conceptually one-pass (after preprocessing), so at this point, the compiler doesn't have the information available to argue with you.
Your actual implementation of f() takes three int arguments, so the calls which only provide one and two arguments invoke undefined behaviour - it's an error which means that the compiler isn't required to give you an error message, and anything could happen when you run the program.
int f();
In C this declares a function which take a variable number of arguments i.e. it's equivalent to the following in C++
int f(...);
To check this use the following instead of int f();
int f(void);
This will cause the compiler to complain.
Please note: A C linker quirk is also involved here...the C linker does not validate the arguments being passed to a function at the point of invocation and simply links to the first public symbol with the same name. Thus the use of f() in main is allowed because of the declaration of int f(). But the linker binds the function f(int, int, int) during link time at the invocation sites. Hope that makes some sense (please let me know if it doesn't)
It runs fine since int f() means what other answer has already said: it means unspecified number of arguments. This mean you can call it with the number of arguments that you want (also more than 3), without the compiler saying anything about it.
The reason why it works "under the cover", is that arguments are pushed on the stack, and then accessed "from" the stack in the f function. If you pass 0 arguments, the i, j, k of the function "corresponds" to values on the stack that, from the function PoV, are garbage. Nonetheless you can access their values. If you pass 1 argument, one of the three i j k accesses the value, the others get garbage. And so on.
Notice that the same reasoning works if the arguments are passed in some other way, but anyway these are the convention in use. Another important aspect of these conventions is that the callee is not responsible for adjusting the stack; it is up to the caller, that knows how many argument are pushed for real. If it would be not so, the definition of f could suggest that it has to "adjust" the stack to "release" three integer, and this would cause a crash of some kind.
What you've written is fine for the current standard (on gcc compiles with no warnings even with -std=c99 -pedantic; there's a warning, but it's about the missing int in front of the f definition), even though many people finds it disgusting and call that an "obsolescent feature". For sure, your usage in the example code does not show any usefulness, and likely it can help busting bugs a more binding usage of prototypes! (But still, I prefer C to Ada)
add
A more "useful" usage of the "feature" that does not trigger the "undefined behaviour" issue, could be
#include<stdio.h>
int f();
int main()
{
f(1);
f(2,2);
f(3,2,3);
}
int f(int i,int j,int k)
{
if ( i == 1 ) printf("%d\n", i);
if ( i == 2 ) printf("%d %d\n", i, j);
if ( i == 3 ) printf("%d %d %d\n", i, j, k);
}
When you compile the same program using g++ compiler you see the following errors -
g++ program.c
program.c: In function `int main()':
program.c:2: error: too many arguments to function `int f()'
program.c:6: error: at this point in file
program.c:2: error: too many arguments to function `int f()'
program.c:7: error: at this point in file
program.c:2: error: too many arguments to function `int f()'
program.c:8: error: at this point in file
program.c: At global scope:
program.c:12: error: ISO C++ forbids declaration of `f' with no type
Using gcc with option -std=c99 just gives a warning
Compile the same program with the same standard which g++ is having by default, gives the following message:
gcc program.c -std=c++98
cc1: warning: command line option "-std=c++98" is valid for C++/ObjC++ but not for C
My answer then would be or c compilers conform to a different standard which is not as restrictive as the one which c++ conforms to.
In C a declaration has to declare at least the return type. So
int f();
declares a function that returns the type int. This declaration doesn't include any information about the parameters the function takes. The definition of the function is
f(int i,int j,int k)
{
printf("%d %d %d",i,j,k);
}
Now it is known, that the function takes three ints. If you call the function with arguments that are different from the definition you will not get a compile-time error, but a runtime error (or if you don't like the negative connotation of error: "undefined behavior"). A C-compiler is not forced by the standard to catch those inconsistencies.
To prevent those errors, you should use proper function prototypes such as
f(int,int,int); //in your case
f(void); //if you have no parameters

Resources