C编译器警告错误

时间:2014-05-10 21:04:54

标签: c

一个简单的程序

#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

这是编译器的错误警告,还是我遗漏的其他东西?

4 个答案:

答案 0 :(得分:5)

编译器对于警告呼叫当然是正确的。具有printf说明符的"%s"需要类型为char*的参数(必须指向字符串),并且您传递的参数不属于该类型。

至于为什么警告消息引用int而不是char,这是因为printf可变参数函数。第一个参数(格式字符串)声明为const char*类型,但以下参数仅指定为, ...。在这种特殊情况下,比int更窄的整数类型的参数提升intunsigned int。因此,即使表达式b的类型为char,传递给printf的实际参数的类型为int;具体而言,这是将b的值从char转换为int的结果。

答案 1 :(得分:1)

警告是准确的,虽然原因有点模糊。

printf()的声明是:

int printf(const char *restrict format, ...);

constrestrict关键字对于此讨论并不重要。重要的是省略号...。当参数传递给具有可变参数列表(可变参数函数)的函数时,它们会经历“默认参数转换”。短于int(各种形式的shortchar)的整数类型会提升为intfloat值会提升为double 。因此,调用可变参数函数的规则将b的值转换为int

"%s"格式需要一个指向以null结尾的字符串的指针。变量b是单个char,而不是字符串。因此,编译器正确地警告您,运行该程序将无法获得良好的结果。

在这种情况下,使用%c(打印字符)或%d(打印十进制整数)等格式可能是最好的:

printf("%c\n", b);

作为一般规则,在C编程职业生涯的这个阶段,你应该假设编译器是正确的,你错了。请记住,C编译器比您更了解C语言。这并不是说编译器中永远不存在错误。但是,你找到一个的可能性很小。直到你对C有足够的了解(可能是五到十年的时间),那么你应该假设编译器是对的,你错了,并找出(a)编译器意味着什么,以及(b)如何修复它。 / p>

并非总是如此。三十年前,糟糕的编译器存在,因为最好的并不是那么好。可以在这些编译器中找到错误。然而,有一个严重的风选,很少有无能的编译器留在市场上。有时您可以找到具有令人惊讶的限制的编译器的地方(偶尔会等同于错误)是专门针对模糊芯片的嵌入式系统。但是,在台式机和服务器(以及平板电脑和智能手机)的主流应用中,您不太可能遇到严重缺陷的编译器。


ISO / IEC 9899:2011§6.5.2.2函数调用

  

¶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编译器消息的人来说)。