scanf正在覆盖第二个变量

时间:2019-05-23 14:43:41

标签: c scanf

我要用户输入两个变量。首先是无符号整数a,然后是无符号字符ba的读入工作正常,但在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)

2 个答案:

答案 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的值的各种问题的重复。 zhh长度修饰符都出现在C99中。

C89对长度修饰符的描述如下

  
      
  • 可选的hl(ell)或L,指示接收对象的大小。如果转换说明符din的前面是h,如果相应的参数是指向short int的指针而不是指向{{ 1}},如果指向int,则使用l。同样,如果相应的参数是指向long int的指针而不是指向o的指针,则转换说明符ux的前面应是hunsigned short int,或者如果指向unsigned int的指针,则按l。最后,如果相应的参数是指向unsigned long int的指针而不是指向{{1}的指针,则转换说明符efg的前面应有K。 },或者如果指向double double的指针,则按float。如果Llongh与任何其他转换说明符一起出现,则行为未定义。
  •   

l长度修饰符出现在C99中。 C11 7.21.6.1p7说:

  

L

     

指定后面的hhhhdiou转换说明符适用于已签名的字符或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