一个简单的程序
#include<stdio.h>
int main() {
char b='a';
printf("%s \n", b);
return 0;
}
输出:
test.c: In function ‘main’:
test.c:4:1: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("%s \n", b);
^
但第二个arg是char
而非int
。
这是编译器的错误警告,还是我遗漏的其他东西?
答案 0 :(得分:5)
编译器对于警告呼叫当然是正确的。具有printf
说明符的"%s"
需要类型为char*
的参数(必须指向字符串),并且您传递的参数不属于该类型。
至于为什么警告消息引用int
而不是char
,这是因为printf
是可变参数函数。第一个参数(格式字符串)声明为const char*
类型,但以下参数仅指定为, ...
。在这种特殊情况下,比int
更窄的整数类型的参数提升到int
或unsigned int
。因此,即使表达式b
的类型为char
,传递给printf
的实际参数的类型为int
;具体而言,这是将b
的值从char
转换为int
的结果。
答案 1 :(得分:1)
警告是准确的,虽然原因有点模糊。
printf()
的声明是:
int printf(const char *restrict format, ...);
const
和restrict
关键字对于此讨论并不重要。重要的是省略号...
。当参数传递给具有可变参数列表(可变参数函数)的函数时,它们会经历“默认参数转换”。短于int
(各种形式的short
和char
)的整数类型会提升为int
,float
值会提升为double
。因此,调用可变参数函数的规则将b
的值转换为int
。
"%s"
格式需要一个指向以null结尾的字符串的指针。变量b
是单个char
,而不是字符串。因此,编译器正确地警告您,运行该程序将无法获得良好的结果。
在这种情况下,使用%c
(打印字符)或%d
(打印十进制整数)等格式可能是最好的:
printf("%c\n", b);
作为一般规则,在C编程职业生涯的这个阶段,你应该假设编译器是正确的,你错了。请记住,C编译器比您更了解C语言。这并不是说编译器中永远不存在错误。但是,你找到一个的可能性很小。直到你对C有足够的了解(可能是五到十年的时间),那么你应该假设编译器是对的,你错了,并找出(a)编译器意味着什么,以及(b)如何修复它。 / p>
并非总是如此。三十年前,糟糕的编译器存在,因为最好的并不是那么好。可以在这些编译器中找到错误。然而,有一个严重的风选,很少有无能的编译器留在市场上。有时您可以找到具有令人惊讶的限制的编译器的地方(偶尔会等同于错误)是专门针对模糊芯片的嵌入式系统。但是,在台式机和服务器(以及平板电脑和智能手机)的主流应用中,您不太可能遇到严重缺陷的编译器。
¶6如果表示被调用函数的表达式具有不包含a的类型 原型,对每个参数执行整数提升,并对其进行参数化 将类型
float
提升为double
。这些被称为默认参数 促销。如果参数的数量不等于参数的数量,则 行为未定义。如果使用包含原型的类型定义函数,并且 原型以省略号(, ...
)或后面的参数类型结束 促销与参数类型不兼容,行为未定义。 如果使用不包含原型的类型定义函数,则使用类型 促销后的参数与之后的参数不兼容 促销,行为未定义,但以下情况除外:
一个提升类型是有符号整数类型,另一个提升类型是 相应的无符号整数类型,该值可在两种类型中表示;
这两种类型都是指向字符类型的限定或非限定版本的指针
void
。
'整数提升'在§6.3.1.8常规算术转换中定义。它们比我想要经历的更复杂。
答案 2 :(得分:0)
一个char实际上只是一个8位数字,所以单独的一个char与一个int没有区别,只是它只能存储较小的数字。在你的printf语句中你有
%s
但是单个字符不被视为字符串,只是一个数字,因此您应该使用
%c or %d
为你的printf语句。如果您有一组字符,那么您将使用%s
答案 3 :(得分:0)
请改为尝试:
printf(&#34;%c \ n&#34;,b);
编译器正在将char转换为int,因此错误消息是有意义的(至少对于用于解释C编译器消息的人来说)。