scanf将整数输入读入uint8_t

时间:2016-03-24 00:29:17

标签: c

有没有办法使用scanf将unsigned char十进制输入读入uint8_t变量?

我担心如果我将%hu或%u读入uint8_t,它可能会破坏相邻的内存,因为uint8_t是一个字节,但%hu是2个字节,%u是4个字节。

我正在使用MinGW32

gcc.exe (GCC) 4.9.3
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

我担心的代码:

/* worried.c - issue demo code. */
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(int argc, char **argv)
{
    uint8_t filler1 = 17;             /* do not corrupt me please. */
    uint8_t my_mem;
    uint8_t filler2 = 39;             /* do not corrupt me please. */ 

    printf("please enter a number: $ ");
    scanf("%u", &my_mem);             /* corrupts fillers... */
    // scanf("%hu", &my_mem);         /* this also corrupts... */
    // scanf("%hhu", &my_mem);        /* still corrupts... */ 
    // scanf("%"SCNu8, &my_mem);      /* still corrupts... */
    // scanf("%"PRIu8 "\n", &my_mem); /* still corrupts... */

    printf("filler1 = %u.\n", filler1);
    printf("my_mem = %u.\n", my_mem);
    printf("filler2 = %u.\n", filler2);         

    return 0;
}

请注意,上面的代码确实破坏了填充程序,这在读取稍后将直接写入二进制(记录)文件的结构时是灾难性的。

我可以通过从一个临时变量中进行转换来解决它,但这对我的程序需要一些额外的工作,我想知道我是否可以避免强制我的程序,并直接读入my_mem。

到目前为止,似乎最有可能的解决方案是:

  

可移植的唯一方法适用于GCC4.9.3和更新版本   通过铸造。在GCC5.2上有更优雅的解决方案,例如%HHU,   但他们在GCC4.9.3上行为不端。

3 个答案:

答案 0 :(得分:1)

我还不能评论,所以我会留下答案。按照其他人的建议使用scanf("%hhu", &my_mem);会删除编译错误:

test.c: In function ‘main’:
test.c:12:11: warning: format ‘%u’ expects argument of type ‘unsigned int *’, but argument 2 has type ‘uint8_t * {aka unsigned char *}’ [-Wformat=]
 scanf("%u", &my_mem);      /* corrupts fillers... */
       ^

并生成正确的输出。

please enter a number: $ 45
filler1 = 17.
my_mem = 45.
filler2 = 39

使用gcc (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010进行测试。

答案 1 :(得分:1)

使用兼容的编译器,使用SCNu8 @BLUEPIXY

#include <stdint.h>
#include <inttypes.h>

if (1 == scanf("%" SCNu8, &my_mem)) Oh_happy_day();

使用较少的编译器,获取新的编译器或使用所有准备好的OP。

unsigned u; 
if (1 == scanf("%u", u)) {
  my_mem = u;
  Oh_somewhat_happy_day();
}

或者自己定义SCNu8(它是一个宏)

#include <stdint.h>
#include <inttypes.h>
#ifndef SCNu8
#define SCNu8 "hhu"
#endif

if (1 == scanf("%" SCNu8, &my_mem)) Oh_happy_day_again();

答案 2 :(得分:1)

您遇到了编译错误。在Windows中使用MinGW会出现此错误,因为scanf调用的默认操作模式是将调用转发到Microsoft C运行时,该运行时不支持%hhu

有一个可以与MinGW一起使用的开关,可以使用自己的scanf实现和其他此类功能,而不是转发给Microsoft。如果使用以下开关进行编译:

-std=c11 -D__USE_MINGW_ANSI_STDIO

然后它可以解决问题。使用此编译器,默认情况下不符合标准,您必须提供各种开关才能使其在标准模式下运行。

我用MinGW-w64 - 已解散的MinGW项目的现代分支 - 和gcc 4.9.2测试了这个,它对我有用。 YMMV