通过省略号发送的“long”和“size_t”的整数提升?

时间:2012-10-12 16:01:17

标签: c integer-promotion

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

由于printf的参数是通过省略号(...)传递的,因此它们会被提升整数。我知道charshortint会升级为int,而long long则不会升级。同样适用于他们的unsigned同行。

这意味着在阅读varargs时,va_arg(args, int)应该用于charshortintva_arg(args, long long)应该用于long long }}

我的问题是,longsize_t是否得到晋升,如果有,我们会做什么?互联网上有很多关于整数提升的消息来源,但我还没有看到有关这些类型的讨论。

P.S。我很感激参考标准。

3 个答案:

答案 0 :(得分:2)

C说(强调我的):

  

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

     

- 具有整数转换等级较小的整数类型的对象或表达式   大于或等于int和unsigned int的等级。

     

- _Bool,int,signed int或unsigned int。

类型的位字段      

如果int可以表示原始类型的所有值,则该值将转换为int;否则,它将转换为unsigned int。这些被称为整数促销.48)整数促销不会改变所有其他类型。

答案 1 :(得分:2)

long的整数转换等级必须大于int(6.3.1.1p1)的等级,因此{em}需要va_arg(args, long),即使 longint具有相同的表示(和精度)。请注意,在大多数64位平台上,long是64位; Windows(LLP64平台)是一个例外。

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的精度小于{{1}的精度1}})或int(如果两种类型具有相同的精度)。在任何一种情况下,您都需要编写unsigned int(即使va_arg(args, unsigned int)参数被提升为size_t,7.16.1.1p2允许使用等效的无符号类型。
  2. int的相同,即intsize_t的类型相同。在这种情况下,允许unsigned intva_arg(args, unsigned int)
  3. 大于va_arg(args, size_t)。在这种情况下,必须使用int
  4. 请注意,即使va_arg(args, size_t)的精度与size_t的精度相同,也可以获得1和3中的任何一个。

    这意味着要使用int提取size_t参数,有必要知道或推断va_arg的整数转换等级。这可以使用类型通用宏(6.5.1.1)来完成:

    size_t

    如果#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_tsize_t的typedef会产生冲突。

    请注意,这是一个不受unsigned int限制的问题,size_tptrdiff_t有同样的问题(对于后者,wchar_t可以容纳任何wint_t }值并且不受推广,但无法保证将wchar_t 提升为wchar_t,这与wint_t被提升为{{的保证不同1}})。我建议标准需要引入新类型charintspromo_t,同样适用于ppromo_t中的类型。 (当然,你可以使用上面的wpromo_t,但这是一个痛苦的问题。)

答案 2 :(得分:1)

类型long的参数不会被提升。与size_t相关的整数促销可归纳如下:

  1. 如果size_t的范围为int,则提升为int
  2. 如果size_t的范围为unsigned int,则提升为unsigned int
  3. 否则,size_t的转化率(以及宽度)高于unsigned int,且不会促销。
  4. 如果size_tunsigned int的别名或宽度大于size_t,则表示非常简单。在这些情况下,不会发生促销,您可以使用size_t来读取可变参数。

    边缘情况是

    • int的范围为size_t
    • int不在unsigned int范围内,但在unsigned int范围内,实际上不是int

    如果size_t包含填充,unsigned int是一个与unsigned int宽度相同的扩展整数类型,则会发生后者。

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