Default argument type for function without prototype?

Hi,

I am a beginner to C and I previously asked this question on SO (and it was marked as duplicate :slight_smile: ) I still do not understand the problem to the end. I understand the need of function prototypes and the default argument promotion machinery. But I am still confused with the obtained warning and final result for this example:

#include <stdio.h>

void impl();

int main(void){

impl(3.0);

return 0;

}

void impl(val){

printf("%.2f", val);

}

I get the following warning: **format specifies type 'double' but the argument has type 'int' [-Wformat].**I can not understand why it is supposed by a compiler that **val** should be treated as **int** and not to skip the number and types of arguments and then perform default argument promotion at run time. Also I read that if you don’t provide argument types in ANSI C:

An ANSI C compiler will assume that you have decided to forego function prototyping, and it will not check arguments.

The result which is printed to the console is 0.00, but as I understood the caller should place double on the stack and **%f** also means double in **printf** so it reads double off the stack, and the result should not be affected.

So I’m still confused what is happening here. Also I can’t find where it is stated that the argument without a type should be treated by a compiler as type **int**. I understand that the question is stupid in nature, for this I apologize in advance, but it somehow sat down in my head and I nowhere can I find why it happens. Thank you!

p.s.: Compiled with **clang 6.0** and **--std=c89** flag under Windows 10. Apologies if this question is off-topic for this list, but i can’t find any other.

With kind regards,

-gdg

Hi Kirill,

Hi,

I am a beginner to C and I previously asked this question on SO (and it was
marked as duplicate :slight_smile: ) I still do not understand the problem to the end.

What is your question that is related to the development of the clang compiler?

I understand the need of function prototypes and the default argument
promotion machinery. But I am still confused with the obtained warning and
final result for this example:

#include <stdio.h>

void impl();

int main(void){

impl(3.0);

return 0;

}

void impl(val){

printf("%.2f", val);

}

I get the following warning: format specifies type 'double' but the argument
has type 'int' [-Wformat].I can not understand why it is supposed by a
compiler that val should be treated as int

Because the C standard says so. Read this StackOverflow answer:
https://stackoverflow.com/a/13950800

especially the part that says: "If no variable type is in front of a
variable in the parameter list, then int is assumed"

When the compiler compiles the "impl" function, it has to assign a
type to the variable "val". The standard says this type has to be
"int". The compiler can't take into account that in main() you're
passing a double to "impl".

and not to skip the number and
types of arguments and then perform default argument promotion at run time.
Also I read that if you don't provide argument types in ANSI C:

An ANSI C compiler will assume that you have decided to forego function
prototyping, and it will not check arguments.

The result which is printed to the console is 0.00, but as I understood the
caller should place double on the stack and %f also means double in printf
so it reads double off the stack, and the result should not be affected.

You wrote "void impl();". This told the compiler not to check the type
of arguments passed to the "impl" function.

Later you wrote "impl(3.0)". The compiler dutifully passed the double
value to the impl function: it loaded the value into the xmm0
register, because the x86-64 calling convention passes the first few
arguments in registers.
(line 7 in https://godbolt.org/g/puW5b1)

Later you wrote "void impl(var)" and called printf. The compiler
passed the string "%.2f" to the printf function as the first argument
(lines 19 and 22), then it passed the integer it received in the rdi
register as the second argument to printf (lines 20 and 21). It also
passed the number of floating point arguments in vector registers
passed to printf in the al register (zero, line 23).

impl expected an int argument in the rdi register. Unfortunately,
because you called impl with a double, the value of rdi contained
garbage. This got passed to printf. I have no idea what printf did
when instructed to print a double (with "%f") and then it was told
that no floating-point values were given to it.

So I'm still confused what is happening here. Also I can't find where it is
stated that the argument without a type should be treated by a compiler as
type int.

See the StackOverflow answer.

I understand that the question is stupid in nature, for this I
apologize in advance, but it somehow sat down in my head and I nowhere can I
find why it happens. Thank you!

p.s.: Compiled with clang 6.0 and --std=c89 flag under Windows 10. Apologies
if this question is off-topic for this list, but i can't find any other.

I don't understand this. A google search for "mailing list" returns
almost eight million results. You could have sent your question to any
of them.

Csaba

Thank you Csaba for the answer and the time spent!

One more time I apologize for an off topic question.

I think the point is that this question is not for the Clang mailing list,
as it isn't a decision made by the Clang developers. What happens in your
example piece of code is dictated by a combination of calling convention
(which registers contain what when calling functions) combined with the
behaviour described in the C standard (why untyped arguments are `int`).
You may want to use a more modern C standard, the code you posted won't
compile as C++, nor will it compile with `-ansi` or `-std=c99`.

The code exhibits undefined behaviour, and you'll almost certainly get a
completely different result on x86-32 machine, yet a different result on an
ARM processor, and in some cases it may well crash or cause some other
"interesting" behaviour. And if you change the code a little bit, for
example add a variable in your `impl` function that uses floating point
calculations, it will do something completely different. Or maybe not...
It's undefined behaviour, so "anything can happen".