【问题标题】:sscanf seems to behave different on uint variables vs int variables in c [duplicate]sscanf 似乎在 uint 变量与 c 中的 int 变量上表现不同 [重复]
【发布时间】:2018-06-30 02:41:34
【问题描述】:

我正在开发一个微控制器程序,并希望使用sscanf() 将字符串中的数字读入整数变量。 问题是我在使用 int 声明与 uint8_tuint16_t 时得到不同的行为。

这是使用int 进行变量声明:

 #include <stdio.h>
 #include <stdint.h>
 int main()
 {
     int power;
     int hr;
     int cadence;
     sscanf("204 67 94","%d %d %d",&power, &hr, &cadence);
     printf("power: %d, hr: %d, cadence: %d", power, hr, cadence);        
     return 0;
 }

当放入https://www.onlinegdb.com/ 时返回:

power: 204, hr: 67, cadence: 94

...Program finished with exit code 0
Press ENTER to exit console.

这是我期望它的行为方式。


而使用uint8_tuint16_t 整数:

#include <stdio.h>
#include <stdint.h>
int main()
{
    uint16_t power;
    uint8_t hr;
    uint16_t cadence;
    sscanf("204 67 94","%d %d %d",&power, &hr, &cadence);
    printf("power: %d, hr: %d, cadence: %d", power, hr, cadence);
    return 0;
}

当放入 https://www.onlinegdb.com/ 时,输出:

power: 0, hr: 67, cadence: 94

...Program finished with exit code 0
 Press ENTER to exit console.

因此,由于某种原因,功率(或更一般地说,它似乎是第一个变量)设置为 0。 谁能指出我正确的方向并解释我做错了什么?

【问题讨论】:

  • 这里的真正问题是您没有将编译器警告提高到足够高以使其能够捕捉到这一点。
  • 真正的问题是您没有阅读手册页 - 请参阅scanf
  • 如果格式说明符与相应变量的类型不匹配,XXXscanf()XXXprintf() 函数会给出未定义的行为。 %d 指定有符号整数类型,并且为相应参数提供任意大小的无符号变量会产生未定义的行为。

标签: c int scanf uint


【解决方案1】:

正确的格式说明符应该是

scanf("%" SCNu16, &power);

使用错误的格式说明符是未定义的行为。你也可以对sscanf 做同样的事情。

sscanf("204","%"SCNu16 ,&power);

uint8_t 也是如此,它将是 SCNu8。同样,对于打印,您将使用正确的 -

printf("%" PRIu16 "\n", power);

还可以编译启用警告的代码 -gcc -Wall -Werror progname.c。您看到的警告 - 尝试努力解决它们。这将帮助您解决大问题。查看sscanf 的手册以了解他们返回的内容 - 检查一下,了解sscanf 调用是否成功。

【讨论】:

    【解决方案2】:

    %d 格式说明符需要一个指向 int 的指针。如果您使用%u,对于无符号值,您必须使用unsigned int。您不能使用其他类型,例如 uint16_tuint8_t。这样做:

    unsigned int power;
    unsigned int hr;
    unsigned int cadence;
    sscanf("204 67 94","%d %d %d",&power, &hr, &cadence);
    

    【讨论】:

    • 使用%d 代替%u 有多大影响?这并不理想;有多严重?
    • 可能没多大关系,但%d 当然会正确扫描一个负数,并在unsigned int 中输入一个实际上不是负数的值。
    • Hmmm...C11 7.21.6.2 fscanf() 说:d — 匹配可选带符号的十进制整数,其格式与 strtol 函数的主题序列的预期格式相同,值为 10为基本论点。相应的参数应该是一个指向有符号整数的指针。 u 的规范是类似的,并指定“指向无符号整数的指针”。严格来说,你如履薄冰。实际上,也许没有那么多。 (我想知道规范中的“在没有尺寸修饰符的情况下”部分是什么意思?)
    【解决方案3】:

    在第二个示例中,您使用了错误的变量类型格式。

    你应该使用来自&lt;inttypes.h&gt;的宏:

     SCNu8   --> uint8_t
     SCNu16  --> uint16_t
    

    对于uint8_t%hu 对于uint16_t,您可能会很安全。

    你的行为很奇怪,因为你对编译器撒了谎;这就是它如何获得自己的回报。不要对你的编译器撒谎!

    【讨论】:

      【解决方案4】:

      解决了!谢谢。

      #include <stdio.h>
      #include <stdint.h>
      #include <inttypes.h>
      int main()
      {
          uint16_t power;
          uint8_t hr;
          uint16_t cadence;
          sscanf("204 67 94","%"SCNu16 "%"SCNu8 "%"SCNu16,&power, &hr, &cadence);
          printf("power: %"PRIu16 " hr: %"PRIu8", cadence: %"PRIu16, power, hr, cadence);
          return 0;
      }
      

      这样做并按预期产生输出。 进一步搜索让我找到了https://stackoverflow.com/a/23748311/9246687,这也有帮助。

      【讨论】:

      • 欢迎来到 Stackoverflow!您当然可以回答自己的问题,但这不是必需的。如果您收到解决问题的答案,您通常应该accept 该答案表明问题已得到您满意的解决。您还应该考虑对您认为有用的答案进行投票,可能包括您接受的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-16
      • 2018-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多