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()
acceptchar
作为类型参数没有意义
但是该语言并不禁止调用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);