C va_arg中的字符类型

C va_arg中的字符类型,c,arguments,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); } 现在

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

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);
}
现在,据我所知,C想要将char类型提升为int。为什么C想要这样做?第二,将int转换回char的最佳解决方案是什么

现在,据我所知,C想要将char类型提升为int。为什么C想要这样做

因为标准是这么说的。如果将转换秩小于
int
(例如
char
bool
short
)的整数值传递给具有可变参数数的函数,则它将转换为
int
。大概原因在于性能,在性能方面(事实上,现在通常仍然如此),传递与机器字边界对齐的值更好

第二,将int转换回char的最佳解决方案是什么

是的,但实际上不需要强制转换,甚至隐式转换也可以:

char ch = va_arg(ap, int);

对变量函数进行了特殊处理

对于非变量函数,原型(声明)指定所有参数的类型。参数可以是任何(非数组、非函数)类型——包括小于
int
的类型

对于可变函数,编译器不知道与
,…
对应的参数类型。出于历史原因,并且为了使编译器的工作更容易,任何小于
int
类型的对应参数都会提升为
int
unsigned int
,任何
float
类型的参数都会提升为
double
。(这就是为什么
printf
float
double
参数使用相同的格式说明符。)

因此,变量函数不能接收
char
类型的参数。您可以使用
char
参数调用这样的函数,但它将被提升为
int

(在C的早期版本中,在引入原型之前,所有函数的行为都是这样的。即使是C11也允许非原型声明,其中狭义的参数被提升为
int
unsigned int
、或
double
。但是考虑到原型的存在,确实没有理由编写依赖于此类pr的代码变量——除了变量函数的特殊情况。)

因此,将
va_arg()
accept
char
作为类型参数没有意义

但是该语言并不禁止调用
va_arg()
;事实上,标准中描述
的部分没有提到参数提升。该规则在函数调用部分6.5.2.2第7段中说明:

如果表示被调用函数的表达式的类型 如果包含原型,参数会隐式转换,如下所示 如果按赋值,则对应参数的类型,取 每个参数的类型是其非限定版本 声明类型。函数原型中的省略号表示法 声明符导致参数类型转换在最后一个 声明的参数。默认参数升级是在 尾随参数

va_arg()
宏7.16.1.1的描述中说(添加了强调):

如果没有实际的下一个参数,或者如果类型与 实际下一个参数的类型(,根据 默认参数升级),行为未定义,但 以下情况:
[剪报]

“默认参数升级”将窄参数转换为
int
无符号int
双精度
。(最大值超过
INT\u MAX
的无符号整数类型的参数将被提升为
unsigned INT
。理论上,
char
可以这样做,但只有在非常不寻常的实现中。)

第二,将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
转换成
unsigned char
并写入
fp
,谢谢Keith。我每天都在学习关于C的新东西。:“但是语言并不禁止[…]”——我在这里迷路了。它没有明确定义:7.16.1.1(
va_arg
)p2”[I]f type与实际下一个参数的类型不兼容(根据默认参数提升),行为未定义,但以下情况除外:[……]“@mafso:undefined behavior并不意味着它被禁止。
va_arg(ap,char)
既不是语法错误,也不是约束冲突;一致性编译器不需要拒绝或诊断它。我同意(我甚至不确定是否允许编译器拒绝带有(未访问的)
va_arg(ap,char)
,GCC警告如果达到代码,程序将中止),我对此感到困惑不管怎么说,我认为这个答案是有用的或没有那个部分的,即使我发现它有点误导。(我会读“禁止”作为“禁止严格遵守代码”,但也许那只是我。)“因为这是错误的。我刚刚更新了它。既不需要强制转换也不需要隐式转换。请参阅我(更新)的答案的结尾。@KeithThompson你说不需要隐式转换是什么意思?当然你不能写
char ch=va_arg(ap,char)
因为它是未定义的?如果要从参数列表中删除
字符
,必须将
int
传递给
va_arg
,是吗
const int c = va_arg(ap, int);
putc(c, fp);