c - 通过省略号发送时 `long` 和 `size_t` 的整数提升?

标签 c integer-promotion

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

由于 printf 的参数是通过省略号 (...) 传递的,因此它们得到整数提升。我知道 charshortint 被提升为 intlong long没有得到提升。对于他们的 unsigned 同行也是如此。

这意味着在读取可变参数时,va_arg(args, int) 应该用于 charshortint va_arg(args, long long) 应该用于 long long

我的问题是,longsize_t 会得到提升吗?如果提升了,会提升到什么位置?互联网上有很多关于整数提升的资料,但我还没有看到任何关于这些类型的资料。

附言如果能引用该标准,我将不胜感激。

最佳答案

要求long的整数转换秩大于int的秩(6.3.1.1p1),所以va_arg(args, long) 是必需的,即使 longint 具有相同的表示形式(和精度)。请注意,在大多数 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的整数转换等级有三种可能:

  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_tunsigned int是同一类型。在这种情况下,允许 va_arg(args, unsigned int)va_arg(args, size_t)
  3. 大于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_tunsigned int 的 typedef,那会发生冲突。

请注意,这是一个不限于size_t的问题,ptrdiff_twchar_t也有同样的问题(对于后者, wint_t 可以包含任何 wchar_t 值并且不受提升,但不能保证 wchar_t 提升为 wint_t,不同于 char 被提升为 int 的保证)。我建议该标准需要引入新类型 spromo_tppromo_twpromo_t,对于 stdint 中的类型也同样如此。 h. (当然,您可以像上面那样使用 _Generic,但这很麻烦。)

关于c - 通过省略号发送时 `long` 和 `size_t` 的整数提升?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12862966/

相关文章:

c - 当我们用负参数调用 Malloc 时会发生什么?

c - 无法使用 GCC/Mingw32 编译器在 C 中使用 "Alt+Space"发送虚拟 key "SendInput()"?

c++ - 当二元运算符两边的符号不同时,提升规则如何工作?

c - `uint_fast32_t` 是否保证至少与 `int` 一样宽?

c - Yoda 条件和整数提升

c - 为什么组合 uint8_t 的两个移位会产生不同的结果?

c - C 中的 Linux 管道

c++ - 为什么无限递归会导致段错误

c - 整体提升/转换:为什么我要关心结果类型的名称?

c - 如何在 Linux 上为 GTK+ 设置 C 开发环境?