When a variable argument function is called in c the integer parameters are promoted to int and floating point parameters are promoted to double
Since the prototype doesn’t specify types for optional arguments, in a call to a variadic function the default argument promotions are performed on the optional argument values. This means the objects of type
char
orshort int
(whether signed or not) are promoted to eitherint
orunsigned int
, as appropriate; and that objects of typefloat
are promoted to typedouble
. So, if the caller passes achar
as an optional argument, it is promoted to anint
, and the function can access it withva_arg (ap, int)
.
int
type should be 4 byte on 32 bit machines and 8 byte on 64 bit machines, is that right?
So I wonder what append when I pass a long long int
to a variable argument function like printf with %lld
format.
And, again, I wonder what append when I pass a long double
variable to printf with %Lf
format (no matter if on 32 or 64 bit machines).
[Edited]
on a 32 bit machine, I tried this:
#include <stdio.h>
int main(void)
{
printf("sizeof(int) %d\n", sizeof(int));
printf("sizeof(long int) %d\n", sizeof(long int));
printf("sizeof(long long int) %d\n", sizeof(long long int));
printf("%lld\n", 1LL<<33);
printf("sizeof(float) %d\n", sizeof(float));
printf("sizeof(double) %d\n", sizeof(double));
printf("sizeof(long double) %d\n", sizeof(long double));
return 0;
}
The result is:
sizeof(int) 4
sizeof(long int) 4
sizeof(long long int) 8
8589934592
sizeof(float) 4
sizeof(double) 8
sizeof(long double) 12
this makes me think that not all parameters are promoted to int
, otherwise I would get printed 0 instead of 8589934592.
Maybe only arguments smaller than int
are promoted to int
. And something similar could be for floating point types.
[Edited]
on a 64 bit machine I run this:
int main(void)
{
printf("sizeof(int) %lu\n", sizeof(int));
printf("sizeof(long) %lu\n", sizeof(long));
printf("sizeof(long long) %lu\n", sizeof(long long));
return 0;
}
and get
sizeof(int) 4
sizeof(long) 8
sizeof(long long) 8
if I understand well the standard, only char
and short
are promoted to int
. I wonder what happen in smaller architecture, such like 16 bit or 8 bit MCU. I think that int
size is dependent by architecture, but I wonder if sizeof(int)
can be 1 on 8 bit architecture. In this case promotion of short
to int
could be impossible unless loosing some bits
"int
type should be 4 byte on 32 bit machines and 8 byte on 64 bit machines, is that right?" No. According to the Standard, int
s must be at least 16 bits in width (§5.2.4.2.1), but there is no further stipulation.
When you pass a long long int
to printf()
it is not subject to the integer promotions (§6.3.1.1 2):
The following may be used in an expression wherever an int or unsigned int may be used:
- An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to the rank of int and unsigned int.
- A bit-field of type _Bool, int, signed int, or unsigned int.
If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.58) All other types are unchanged by the integer promotions.
If you pass a long double
to printf()
no conversion is made (§6.5.2.2 6):
If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions.
The conversion specifiers corresponding to the arguments in the printf()
statement have no bearing on these promotions and conversions, except insofar as there will be undefined behavior if the specifiers and the types of their corresponding arguments do not match.
So, the integer promotions are performed, and float
s are converted to double
s, but "No other conversions are performed implicitly" (§6.5.2.2 8).
Addressing your edit to the question: "this makes me think that not all parameters are promoted to int
." Correct. Only integer types with integer conversion rank "less than or equal to the rank of int
and unsigned int
" are subject to integer promotion. It is simpler for floating point types; float
s are promoted to double
. That is all.
It may be worth pointing out that, according to §6.2.5 10, there are three real floating point types, float
, double
, and long double
. The values which may be held by a float
are a subset of the values which may be held by a double
, which are in turn a subset of the values which may be held by a long double
. Hence, there is no possibility of promotion for long double
types.
Further, according to §6.3.1.1 1:
The rank of long long int shall be greater than the rank of long int, which shall be greater than the rank of int, which shall be greater than the rank of short int, which shall be greater than the rank of signed char.
So there is no possibility of a long long int
or long int
ever being promoted to int
or unsigned int
.
As for your final concern that promotion of a short
to an int
may, in some implementation, be impossible without losing some bits, note that §6.2.5 8 guarantees that an int
must be able to contain a short
, since the conversion rank of an int
must be greater than that of a short
:
For any two integer types with the same signedness and different integer conversion rank (see 6.3.1.1), the range of values of the type with smaller integer conversion rank is a subrange of the values of the other type.
int type should be 4 byte on 32 bit machines and 8 byte on 64 bit machines, is that right?
Probably not. First of all, C makes no guarantees about the size of int
, apart from stating that it must be at least 2 bytes (capable of at least holding the value 2^16/2 - 1 = 32767). Nothing in C prevents int
from being 8 bytes, but that's not very convenient.
The convention is: all 8- and 16 bit computers use 16 bit int
. All other computers use 32 bit int
. This is industry de facto standard. Any deviations from this convention would be very exotic, although in theory allowed by C.
So I wonder what append when I pass a long long int to a variable argument function like printf with %lld format.
You get a long long int. No promotion takes place, because the variable is not one of the mentioned small types. The format specifier used is irrelevant to the promotion rules.
this makes me think that not all parameters are promoted to int
Indeed. Only the types that the standard mentions are promoted. The formal definition of the default argument promotions can be found in C11 6.5.2.2/6:
...the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions.
Meaning that only the small integer types (see the integer promotion rule) and float
gets promoted. No other types.
Why you think that your examples printing various type sizes have any relevance in relation to the default argument promotions, I have no idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With