编译时
signed char x=1;
printf("%d",x);
有了mingw,我收到以下警告:
format '%d' expects argument of type 'int *', but argument 2 has type 'signed char *' [-Wformat=]
我知道%d
打印十进制整数而不是字符,还有一个(签名)char指针作为第二个参数传递。但是x
不应该被提升为int然后被正确打印?
为什么mingw在这里警告我?
编辑:对不起,这个警告实际上是由scanf调用产生的:
signed char x;
scanf("%d",&x);
(其他代码在没有警告的情况下编译。)
我认为这是因为scanf会尝试为int编写字节数,而我只保留了char的存储空间,这可能会产生运行时错误......?
答案 0 :(得分:0)
参数的类型必须与相应的转换说明符匹配,或者行为是 undefined ,这意味着编译器不必以任何特定的方式处理这种情况;您甚至收到警告的事实是因为编译器编写者超出了标准的要求(并且因为它是常见的错误)。
问题是%d
指定相应的参数指向类型为int
的对象,该对象很可能大于char
类型的对象。您的scanf
调用假设它有sizeof (int)
个字节要写入,但您要写入的对象只有1个字节宽(根据定义sizeof (char) == 1
)。一个可能的后果是写入错误的字节,导致最好意外输入。
例如,假设sizeof (int)
== 4,x
的地址为0x4000
,并且这是 big-endian 架构,意味着多字节类型中的最高有效字节存储在指定的地址。这就是内存在x
:
+----+
0x4000: | 01 | <-- x
+----+
0x4001: | ?? |
+----+
0x4002: | ?? |
+----+
0x4003: | ?? |
+----+
其中??
表示未知字节值。现在,假设在scanf
来电中输入2
。由于转换说明符为%d
,因此scanf
调用将假定它正在写入int
对象,这意味着您的内存将如下所示:
+----+
0x4000: | 00 | <-- x
+----+
0x4001: | 00 |
+----+
0x4002: | 00 |
+----+
0x4003: | 02 |
+----+
当您检查x
时,它将包含0
,这不是您所期望的。此外,x
之外的内存已被修改,这可能会导致其他问题。
同样,这是基于特定架构细节的一个可能的结果;在小端架构上,它似乎可以工作,因为最不重要的字节位于0x4000
,但你仍然在该对象的边界外写字。
修改强>
正如DevSolar指出的那样,如果您打算读取数值并将它们存储到%hhd
对象(即,您希望存储值),则应该使用char
转换说明符 2
而非字符 '2'
)。如果要存储单个字符值('2'
,'a'
,'?'
等),请使用%c
转换说明符。
答案 1 :(得分:-1)
它警告你,因为你应写了......
signed char x = 1;
printf( "%hhd", x ); // 'hh' length modifier to indicate char argument
此外,请参阅Blue Moon的评论:关于指针类型的错误消息表示scanf()
,而不是printf()
,以及scanf()
中的错误长度修饰符是彻头彻尾的致命(将sizeof( int )
个字节写入只能sizeof( signed char )
...的地方。
如果不明显,长度修饰符也适用于scanf()
:
signed char x;
if ( scanf( "%hhd", &x ) == 1 )
{
// do yourself a favor and DO check scanf() success
// before acting on the results
}