va_arg中的char类型

时间:2015-01-20 20:03:56

标签: c arguments

我有以下函数将传递的参数写入二进制文件。

void writeFile(FILE *fp, const int numOfChars, ...)
{
   va_list ap;
   va_start(ap, numOfChars);
   for(int i = 0; i < numOfChars; i++)
   {
      const char c = va_arg(ap, char);
      putc(c, fp);
   }
   va_end(ap);
}

编译后,我从编译器收到以下警告

 warning: second argument to 'va_arg' is of promotable type 'char'; this va_arg
      has undefined behavior because arguments will be promoted to 'int' [-    Wvarargs]

据我了解,C想要将char类型提升为int。为什么C想要这样做?第二,是将int转换回char的最佳解决方案吗?

2 个答案:

答案 0 :(得分:7)

  

据我了解,C想要将char类型提升为int。为什么C想要这样做?

因为这就是标准所说的。如果您将转化等级小于int(例如charboolshort)的积分值传递给采用可变数量参数的函数,它将会转换为int。据推测,其原因在于其性能,其中(实际上,现在通常仍然是如此)更好地传递与机器字边界对齐的值。

  

其次,是将int转换回char的最佳解决方案吗?

是的,但你甚至不需要强制转换,隐式转换会:

char ch = va_arg(ap, int);

答案 1 :(得分:5)

特殊处理变体函数。

对于非可变函数,prototype(声明)指定所有参数的类型。参数可以是任何(非数组,非函数)类型 - 包括比int窄的类型。

对于可变函数,编译器不知道与, ...对应的参数类型。由于历史原因,为了使编译器的工作更容易,任何比int更窄的类型的相应参数都被提升为intunsigned int,以及任何类型为{的参数{1}}被提升为float。 (这就是doubleprintffloat参数使用相同格式说明符的原因。)

因此,可变参数函数无法接收类型为double参数。您可以使用char参数调用此类函数,但会将其提升为char

(在C的早期版本中,在引入原型之前,所有函数都以这种方式运行。甚至C11也允许非原型声明,其中窄参数被提升为int,{ {1}},或int。但鉴于原型的存在,我们没有理由编写依赖于此类促销的代码 - 除了可变函数的特殊情况。)

正因为如此,unsigned int接受double作为类型参数毫无意义。

但该语言并未禁止 va_arg()的这种调用;实际上,描述char的标准部分并未提及论证推广。该规则在函数调用部分N1570 6.5.2.2第7段:

中说明
  

如果表示被调用函数的表达式具有类型   确实包含一个原型,参数被隐式转换为   如果通过赋值,对相应参数的类型,采取   每个参数的类型是其不合格的版本   声明的类型。函数原型中的省略号表示法   声明器导致参数类型转换在最后一个之后停止   声明参数。执行默认参数促销   尾随论据。

&#34;默认参数促销&#34;将较窄的参数转换为va_arg()<stdarg.h>int。 (最大值超过unsigned int的无符号整数类型的参数将被提升为double。从理论上讲,INT_MAX可能会以这种方式运行,但仅限于不寻常的实施。)

  

其次,是将int转换回char的最佳解决方案吗?

不,不是在这种情况下。铸造很少是必要的;在大多数情况下,隐式转换可以完成相同的工作。在这种特殊情况下:

unsigned int

char的第一个参数已经是const char c = va_arg(ap, char); putc(c, fp); 类型,因此最好写成:

putc

int值由const int c = va_arg(ap, int); putc(c, fp); 转换为int并写入putc