我要用户输入两个变量。首先是无符号整数a
,然后是无符号字符b
。 a
的读入工作正常,但在b
中读入后,a
为0。
我发现指向a
的指针比指向b
的指针大一个。我意识到当b
大于255 a
时不再为0。因此在我看来scanf
读入b
的多个字节并覆盖a
。
#include <stdio.h>
int main ()
{
unsigned int a;
unsigned char b;
printf("a: ");
scanf("%u", &a); /* 255 */
printf("b: ");
scanf("%hhu", &b); /* 17 */
printf("a: %u\n", a); /* a: 0 */
printf("b: %u\n", b); /* b: 17 */
printf("pointer a: %u\n", &a); /* pointer a: 6422316 */
printf("pointer b: %u\n", &b); /* pointer b: 6422315 */
return 0;
}
由于我是C语言编程的新手,所以我不确定了解我的问题所需的信息是什么。我正在使用64位处理器,这是使用的编译器:
gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/8.2.0/lto-wrapper.exe
Target: mingw32
Configured with: ../src/gcc-8.2.0/configure --build=x86_64-pc-linux-gnu --host=mingw32 --target=mingw32 --prefix=/mingw --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-pkgversion='MinGW.org GCC-8.2.0-3' --with-gmp=/mingw --with-mpfr=/mingw --with-mpc=/mingw --enable-static --enable-shared --enable-threads --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --with-isl=/mingw --enable-libgomp --disable-libvtv --enable-nls --disable-build-format-warnings
Thread model: win32
gcc version 8.2.0 (MinGW.org GCC-8.2.0-3)
答案 0 :(得分:5)
问题出在这一行:
scanf("%hhu", &b); /* 17 */
Microsoft的C运行时库未实现%hhu
(它不是C99之前的C标准的一部分)。这导致输入被解释为short
(由于MSVCRT如何在格式说明符中将hh
解释为h
),并超出b
的限制写入并覆盖a
的一部分。
要解决此问题,请将a
的类型更改为unsigned short
,然后将%hu
用作格式说明符,或将-D__USE_MINGW_ANSI_STDIO
标志传递给编译器。
答案 1 :(得分:5)
这几乎是关于在用MinGW编译的代码中用size_t
打印%zu
的值的各种问题的重复。 z
和hh
长度修饰符都出现在C99中。
C89对长度修饰符的描述如下
- 可选的
h
,l
(ell)或L
,指示接收对象的大小。如果转换说明符d
,i
和n
的前面是h
,如果相应的参数是指向short int
的指针而不是指向{{ 1}},如果指向int
,则使用l
。同样,如果相应的参数是指向long int
的指针而不是指向o
的指针,则转换说明符u
和x
的前面应是h
。unsigned short int
,或者如果指向unsigned int
的指针,则按l
。最后,如果相应的参数是指向unsigned long int
的指针而不是指向{{1}的指针,则转换说明符e
,f
和g
的前面应有K。 },或者如果指向double
double的指针,则按float
。如果L
,long
或h
与任何其他转换说明符一起出现,则行为未定义。
l
长度修饰符出现在C99中。 C11 7.21.6.1p7说:
L
指定后面的
hh
,hh
,d
,i
,o
或u
转换说明符适用于已签名的字符或unsigned char参数(该参数将根据整数提升进行提升,但在打印之前将其值转换为signed char或unsigned char);或者后面的x
转换说明符适用于指向带符号的char参数的指针。
MinGW使用MSVCRT.DLL作为C库-该库仅支持 C89。根据C89,看到X
的行为是 undefined ,但这与将其解释为n
并在处写入%hhu
值是一致的从%hu
开始的2 个字节。
解决方案是将值读取到临时unsigned short
或&a
中,然后将其分配给unsigned short
。