的整数转换等级long需要大于int(6.3.1.1p1) 的等级,因此即使具有与 相同的表示(和精度)va_arg(args, long)也是必需的。请注意,在大多数 64 位平台上,是 64 位;Windows(一个 LLP64 平台)是一个例外。 longintlong
size_t要求为无符号整数类型(6.5.3.4p5,7.19p2),建议整数转换秩不大于long int(7.19p4);要求其精度至少为 16 位(7.20.3p2,最小值SIZE_MAX)。它不需要是(typedef to 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相同,也可以获得 1 和 3 中的任何一个int。
这意味着要size_t使用 提取参数va_arg,必须知道或推断 的整数转换等级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,或者是 typedef unsigned int,那么我们提取一个unsigned int; 如果它没有被提升并且是与 不同的类型unsigned int,那么我们就成功了default。我们不能将size_t自身作为选项提供,因为如果size_t是 typedef for会发生冲突unsigned int。
请注意,这是一个不限于 的问题size_t,ptrdiff_t并且wchar_t具有相同的问题(对于后者,wint_t可以保持任何wchar_t值并且不受提升,但不能保证提升到,与提升到 的保证wchar_t 不同)。我建议标准需要为. (当然,你可以像上面那样使用,但它是在脖子上的痛苦。)wint_tcharintspromo_tppromo_twpromo_tstdint.h_Generic