当在 c 中调用可变参数函数时,整数参数被提升为 int,浮点参数被提升为 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
类型在 32 位机器上应该是 4 字节,在 64 位机器上应该是 8 字节,对吗?
所以我想知道当我将 long long int
传递给可变参数函数(如 printf 和 %lld
格式时,附加什么。
而且,我再次想知道当我将一个 long double
变量传递给具有 %Lf
格式的 printf 时会附加什么(无论是在 32 位还是 64 位机器上)。
[已编辑]
在 32 位机器上,我试过这个:
#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;
}
结果是:
sizeof(int) 4
sizeof(long int) 4
sizeof(long long int) 8
8589934592
sizeof(float) 4
sizeof(double) 8
sizeof(long double) 12
这让我觉得并非所有参数都被提升为 int
,否则我将打印 0 而不是 8589934592。
也许只有小于 int
的参数才会被提升为 int
。类似的东西可能适用于浮点类型。
[已编辑]
在 64 位机器上我运行这个:
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;
}
得到
sizeof(int) 4
sizeof(long) 8
sizeof(long long) 8
如果我很好地理解标准,只有 char
和 short
被提升为 int
。我想知道在较小的架构中会发生什么,例如 16 位或 8 位 MCU。我认为 int
大小取决于体系结构,但我想知道 sizeof(int)
在 8 位体系结构上是否可以为 1。在这种情况下,将 short
提升为 int
是不可能的,除非丢失一些位
最佳答案
“int
类型在 32 位机器上应该是 4 字节,在 64 位机器上应该是 8 字节,对吗?”编号。根据标准,int
s must be at least 16 bits in width (§5.2.4.2.1) , 但没有进一步规定。
当您将 long long int
传递给 printf()
时,它不受 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.
如果将long double
传递给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.
与 printf()
语句中的参数对应的转换说明符对这些提升和转换没有影响,除非说明符及其相应参数的类型会出现未定义的行为不匹配。
因此,执行了整数提升,float
被转换为 double
,但是 "No other conversions are performed implicitly" (§6.5.2.2 8) .
解决您对问题的编辑:“这让我认为并非所有参数都提升为 int
。”正确的。只有整数转换等级“小于或等于 int
和 unsigned int
”的整数类型才能进行整数提升。对于浮点类型来说更简单; float
被提升为 double
。就是这样。
可能值得指出的是,根据 §6.2.5 10 , 共有三种真正的浮点类型,float
、double
和long double
。 float
可能持有的值是 double
可能持有的值的子集,后者又是可能持有的值的子集通过 long double
。因此,不可能对 long double
类型进行提升。
进一步,根据§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.
因此 long long int
或 long int
不可能被提升为 int
或 unsigned int
.
至于您最后担心的是,在某些实现中,将 short
提升为 int
可能无法在不丢失一些位的情况下实现,请注意 §6.2.5 8保证 int
必须能够包含 short
,因为 int
的转换等级必须大于 短
:
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.
关于c - 更好地理解 c 中可变参数的类型提升,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44421125/