【问题标题】:scanf read integer input into uint8_tscanf 将整数输入读入 uint8_t
【发布时间】:2016-03-24 00:29:16
【问题描述】:

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

我担心如果我将 %hu 或 %u 读入一个 uint8_t,它可能会损坏相邻的内存,因为 uint8_t 是 1 个字节,但 %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 上有更优雅的解决方案,例如%h, 但他们在 GCC4.9.3 上行为不端。

【问题讨论】:

  • scanf("%" SCNu8, &amp;my_mem);(使用#include &lt;inttypes.h&gt;
  • 我试过了,好像不能编译。导入header后也不知道SCNu8是什么。
  • @BLUEPIXY 是对的。但是,如果您只关心scanf() 的类型小于short,则可以使用%hhuscanf()unsigned char
  • scanf("%hhu", &my_mem);将两个填充符都变为 0 :\
  • 无法复制。 "%hhu""%"SCNu8 都可以正常工作。

标签: c


【解决方案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();

【讨论】:

  • 遗憾的是,必须检查代码中的编译器使其不必要地变得更加复杂,不妨只使用强制转换。如果是这种情况,那么答案将是没有可移植的方式来做我想做的事,我应该总是直接投射。
  • @Dmitry 我怀疑您的标准包含文件缺少的不仅仅是SCNu8 并且需要许多修复。将这些修复收集到一个包含文件中并使用该包含比在整个代码中采用弱实践更好。
【解决方案2】:

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

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

-std=c11 -D__USE_MINGW_ANSI_STDIO

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

我使用MinGW-w64(已解散的 MinGW 项目的现代分支)和 gcc 4.9.2 对此进行了测试,它对我有用。 YMMV

【讨论】:

  • 等等,所以它在 gcc4.9.2 w64 上对你有用,但在 gcc 4.9.3 w32 上对我不起作用?并且 MinGW 管理器没有更新?
  • 您可能正在使用已失效的 MinGW 而不是当前的 MinGW(称为 mingw-w64)。当前版本修复了错误。
  • 我刚刚使用顶部的“获取最新版本”链接从sourceforge.net/projects/mingw/files/MinGW 重新安装了它,错误仍然存​​在,并且 gcc 版本没有改变。即使有旗帜。
  • 我已经在sourceforge.net/p/mingw/bugs/2292 报告了这个错误。可能做错了(我放错了讨论链接,但我在讨论中添加了注释)但这是一种学习体验。
  • @Dmitry 已失效(第三次)
猜你喜欢
  • 2021-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-19
相关资源
最近更新 更多