Questions about C Function Prototypes and Compilation

With the following code:

int main(){
    printf("%fn",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("%fn",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

链接地址: http://www.djcxy.com/p/79908.html

上一篇: ANSI C:从calloc API返回测试结果

下一篇: 关于C函数原型和编译的问题