c - 更好地理解 c 中可变参数的类型提升

标签 c floating-point int printf c99

当在 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 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 类型在 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

如果我很好地理解标准,只有 charshort 被提升为 int。我想知道在较小的架构中会发生什么,例如 16 位或 8 位 MCU。我认为 int 大小取决于体系结构,但我想知道 sizeof(int) 在 8 位体系结构上是否可以为 1。在这种情况下,将 short 提升为 int 是不可能的,除非丢失一些位

最佳答案

int 类型在 32 位机器上应该是 4 字节,在 64 位机器上应该是 8 字节,对吗?”编号。根据标准,ints 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。”正确的。只有整数转换等级“小于或等于 intunsigned int”的整数类型才能进行整数提升。对于浮点类型来说更简单; float 被提升为 double。就是这样。

可能值得指出的是,根据 §6.2.5 10 , 共有三种真正的浮点类型,floatdoublelong doublefloat 可能持有的值是 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 intlong int 不可能被提升为 intunsigned 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/

相关文章:

c++ - 由 4 个十六进制字符组成的数字

c - Windows系统编程

c - 在 PIC32 上通过 DMA 接收 SPI 数据

mysql - 为什么 MySQL 将 float 6.099999904632568 截断为 6.1

swift - 浮点值的 "binade"有什么意义

python - 错误 "invalid literal for int() with base 10:"不断出现

c - C中如何知道avl节点状态?

c - 使用 %S 时出现异常错误

C++17 和十进制浮点的当前状态

java - 扫描仪跳过数字 Java