Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 333
Daniel Scocco Avatar asked Apr 18 '13 13:04

Daniel Scocco


People also ask

Is function prototype mandatory for every user defined function in C?

It is not required, but it is bad practice not to use prototypes. With prototypes, the compiler can verify you are calling the function correctly (using the right number and type of parameters).

Why function prototype is necessary in C?

The function prototypes are used to tell the compiler about the number of arguments and about the required datatypes of a function parameter, it also tells about the return type of the function. By this information, the compiler cross-checks the function signatures before calling it.

What is used to specify the prototype of a function in C?

D. Explanation: A function prototype in C or C++ is a declaration of a function that omits the function body but does specify the function's name, argument types and return type. While a function definition specifies what a function does, a function prototype can be thought of as specifying its interface.

Why is it considered good programming practice to use function prototypes?

In modern C programming, it is considered good practice to use prototype declarations for all functions that you call. As we mentioned, these prototypes help to ensure that the compiler can generate correct code for calling the functions, as well as allowing the compiler to catch certain mistakes you might make.


1 Answers

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.

like image 130
Sergey Kalinichenko Avatar answered Sep 28 '22 04:09

Sergey Kalinichenko