Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
827 views
in Technique[技术] by (71.8m points)

c - Passing float to a function with int argument (that is not declared beforehand)

I have read Garbage value when passed float values to the function accepting integer parameters answers. My question goes a bit deeper. I could have also asked there had I more than 50 reputation point. I am adding my code for more clarification:

#include <stdio.h>
#include <string.h>

void p2(unsigned int tmp)
{
    printf("From p2: 
");
    printf("tmp = %d ,In hex tmp = %x
", tmp, tmp);
}

int main()
{
    float fvar = 45.65;

    p1(fvar);
    p2(fvar);
    printf("From main:
");
    printf("sizeof(int) = %lu, sizeof(float) = %lu
", sizeof(int),
            sizeof(float));
    unsigned int ui;
    memcpy(&ui, &fvar, sizeof(fvar));
    printf("fvar = %x
", ui);
    return 0;
}

void p1(unsigned int tmp)
{
    printf("From p1: 
");
    printf("tmp = %d ,In hex tmp = %x
", tmp, tmp);
}

The output is:

From p1: 
tmp = 1 ,In hex tmp = 1
From p2: 
tmp = 45 ,In hex tmp = 2d
From main:
sizeof(int) = 4, sizeof(float) = 4
fvar = 4236999a8

Passing a float value to a function that is declared beforehand (i.e. p2) with int arguments gives the correct result. When trying the same with a function that is not declared beforehand (i.e. p1) gives incorrect values. And I know the reason that compiler won't assume any type or arity of arguments for the function not declared before handed. That's why float value does not get typecasted to int in the case of p2.

My confusion is, in the case of p2, how exactly does float value get copied to local int variable tmp.

If it is 'bit by bit copy' than reading those locations should yield something (except 1) in hex at least (if not in integer). But that does not sound the case as output shows. I know that float representation is different.

And how p2 may read registers/stack locations that floats weren't copied to? as simonc suggested in the linked question?

I have included the size of int and float both and my compiler is gcc if that helps.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The C programming language is essentially a single-scan language - a compiler doesn't need to reread the code but it can assemble it line by line, retaining information only on how identifiers were declared.

The C89 standard had the concept of implicit declaration. In absence of a declaration, the function p1 is declared implicitly as int p1(); i.e. a function that returns an int and takes unspecified arguments that go through default argument promotions. When you call such a function giving it a float as an argument, the float argument is promoted to a double, as called for by default argument promotions. It would be fine if the function was int p1(double arg); but the expected argument type is unsigned int, and the return value is not compatible either (void vs int). This mismatch will cause the program to have undefined behaviour - there is no point in reasoning what is happening then. However, there are many old C programs that would fail to compile, if the compilers wouldn't support the archaic implicit declarations - thus you just need to consider all these warnings as errors.

Notice that if you change the return value of p1 into an int, you will get less warnings:

% gcc implicit.c
implicit.c:14:5: warning: implicit declaration of function ‘p1’ [-Wimplicit-function-declaration]
 p1(fvar);
 ^~

But the observed behaviour on my compiler would be mostly the same.

Thus the presence of mere warning: implicit declaration of function ‘x’ is quite likely a serious error in newly written code.

Were the function declared before its use, as is case with p2, then the compiler knows that it expects an unsigned long as the argument, and returns void, and therefore it would know to generate correct conversion code from float to unsigned long for the argument.


The C99 and C11 do not allow implicit function declarations in strictly-conforming programs - but they also do not require a conforming compiler to reject them either. C11 says:

An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator).

and a footnote noting that

Thus, an undeclared identifier is a violation of the syntax.

However, it doesn't require a compiler to reject them.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...