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
398 views
in Technique[技术] by (71.8m points)

floating point - better understanding type promotion of variadic parameters in c

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 or short int (whether signed or not) are promoted to either int or unsigned int, as appropriate; and that objects of type float are promoted to type double. So, if the caller passes a char as an optional argument, it is promoted to an int, and the function can access it with va_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
", sizeof(int));
    printf("sizeof(long int) %d
", sizeof(long int));
    printf("sizeof(long long int) %d
", sizeof(long long int));
    printf("%lld
", 1LL<<33);

    printf("sizeof(float) %d
", sizeof(float));
    printf("sizeof(double) %d
", sizeof(double));
    printf("sizeof(long double) %d
", 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
", sizeof(int));
    printf("sizeof(long) %lu
", sizeof(long));
    printf("sizeof(long long) %lu
", 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

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

"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, ints 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 floats are converted to doubles, 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; floats 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.


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

...