从实现 printf
的人的角度来看这个问题。
由于 printf
的参数是通过省略号 (...
) 传递的,因此它们得到整数提升。我知道 char
、short
和 int
被提升为 int
而 long long
没有得到提升。对于他们的 unsigned
同行也是如此。
这意味着在读取可变参数时,va_arg(args, int)
应该用于 char
、short
和 int
而 va_arg(args, long long)
应该用于 long long
。
我的问题是,long
和 size_t
会得到提升吗?如果提升了,会提升到什么位置?互联网上有很多关于整数提升的资料,但我还没有看到任何关于这些类型的资料。
附言如果能引用该标准,我将不胜感激。
最佳答案
要求long
的整数转换秩大于int
的秩(6.3.1.1p1),所以va_arg(args, long)
是必需的,即使 long
与int
具有相同的表示形式(和精度)。请注意,在大多数 64 位平台上,long
是 64 位的; Windows(LLP64 平台)是个异常(exception)。
size_t
要求为无符号整数类型(6.5.3.4p5、7.19p2),建议整数转换秩不大于long int
(7.19p4);要求精度至少为 16 位(7.20.3p2,SIZE_MAX
的最小值)。它不需要是(typedef 到 a)标准整数类型,尽管它是允许的。
那么size_t
的整数转换等级有三种可能:
- 它小于
int
的精度,因此size_t
参数将被提升为int
(如果的精度size_t
小于int
) 或unsigned int
(如果两种类型具有相同的精度)。在任何一种情况下,您都需要编写va_arg(args, unsigned int)
(即使size_t
参数被提升为int
,使用等效的7.16.1.1p2 允许无符号类型。 - 与
int
相同,即size_t
与unsigned int
是同一类型。在这种情况下,允许va_arg(args, unsigned int)
或va_arg(args, size_t)
。 - 大于
int
。在这种情况下,必须使用va_arg(args, size_t)
。
请注意,即使size_t
的精度与int
的精度相同,1和3中的任何一个都可以获得。
这意味着要使用va_arg
提取size_t
参数,需要知道或推断size_t
的整数转换等级。这可以使用泛型宏 (6.5.1.1) 来完成:
#define va_arg_size_t(args) _Generic((+(sizeof(0))), \
int: (size_t) va_arg((args), unsigned int), \
unsigned int: (size_t) va_arg((args), unsigned int), \
default: va_arg((args), size_t))
如果 size_t
被上面使用的一元加运算符提升为 int
,那么我们提取一个 unsigned int
;如果 size_t
被提升为 unsigned int
,或者是 unsigned int
的 typedef,那么我们提取一个 unsigned int
;如果它没有被提升并且是与 unsigned int
不同的类型,那么我们会点击 default
block 。我们不能提供 size_t
本身作为选项,因为如果 size_t
是 unsigned int
的 typedef,那会发生冲突。
请注意,这是一个不限于size_t
的问题,ptrdiff_t
和wchar_t
也有同样的问题(对于后者, wint_t
可以包含任何 wchar_t
值并且不受提升,但不能保证 wchar_t
提升为 wint_t
,不同于 char
被提升为 int
的保证)。我建议该标准需要引入新类型 spromo_t
、ppromo_t
和 wpromo_t
,对于 stdint 中的类型也同样如此。 h
. (当然,您可以像上面那样使用 _Generic
,但这很麻烦。)
关于c - 通过省略号发送时 `long` 和 `size_t` 的整数提升?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12862966/