3

从实施的人的角度来看这个问题printf

由于 的参数printf通过省略号 ( ...) 传递,因此它们得到整数提升。我知道charshort并且int升职intlong long不会升职。对于他们的unsigned同行也是如此。

这意味着在读取可变参数时,va_arg(args, int)应该使用 for charshort而应该使用intwhile 。va_arg(args, long long)long long

我的问题是,做longsize_t获得晋升,如果他们这样做,晋升到什么级别?互联网上有很多关于整数提升的资源,但我还没有看到任何关于这些类型的信息。

PS我希望能参考该标准。

4

3 回答 3

2

C 说(强调我的):

(C99, 6.3.1.1p2) " 在表达式中可以使用 int 或 unsigned int 的任何地方都可以使用以下内容:

— 整数类型的对象或表达式,其整数转换等级小于或等于 int 和 unsigned int 的等级。

— _Bool、int、signed int 或 unsigned int 类型的位域。

如果一个 int 可以表示原始类型的所有值,则将该值转换为 int;否则,它将转换为无符号整数。这些被称为整数提升。48)所有其他类型都不受整数提升的影响。"

于 2012-10-12T16:13:11.867 回答
2

的整数转换等级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

  1. 它小于 的int,因此size_t参数将被提升为int(如果 的精度size_t小于 的int)或unsigned int(如果两种类型具有相同的精度)。无论哪种情况,您都需要编写va_arg(args, unsigned int)(即使size_t参数被提升为int,7.16.1.1p2 也允许使用等效的无符号类型)。
  2. 与 的相同int,即size_t与 的类型相同unsigned int。在这种情况下,要么 要么va_arg(args, unsigned int)va_arg(args, size_t)允许。
  3. 它大于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_tptrdiff_t并且wchar_t具有相同的问题(对于后者,wint_t可以保持任何wchar_t值并且不受提升,但不能保证提升到,与提升到 的保证wchar_t 不同)。我建议标准需要为. (当然,你可以像上面那样使用,但它是在脖子上的痛苦。)wint_tcharintspromo_tppromo_twpromo_tstdint.h_Generic

于 2012-10-12T17:16:45.090 回答
1

类型的参数long不会被提升。相关的整数促销size_t可以总结如下:

  1. 如果size_t在范围内int,提升到int
  2. 如果size_t在范围内unsigned int,提升到unsigned int
  3. 否则,size_t转换排名(因此宽度)大于unsigned int并且不会发生促销

最简单的情况是 ifsize_t是 的别名 或 具有比 更大的宽度unsigned int。在这些情况下,不会发生任何促销活动,您可以使用size_t来阅读可变参数。

边缘情况是

  • size_t在范围内int
  • size_t不在范围内int,但在范围内unsigned int但实际上不存在unsigned int

int如果包含 if 的填充size_t是与 . 相同宽度的扩展整数类型,则后者可能发生unsigned int

假设整数表示包含填充位,您可以通过读取unsigned int可变参数来覆盖这两种边缘情况,这将适用于 C 语言的所有合理实现,尽管可能是未定义的行为。

于 2012-10-12T16:51:37.443 回答