数据类型为 unsigned char 时 scanf 的行为问题

Posted

技术标签:

【中文标题】数据类型为 unsigned char 时 scanf 的行为问题【英文标题】:A problem with the behaviour of scanf when data type is unsigned char 【发布时间】:2020-08-07 16:01:45 【问题描述】:

所以我不知道为什么会观察到这种行为:

#include <stdio.h>

int main()

    unsigned char c;
    char d;
    scanf("%hhu", &d);
    printf("%c\n", d);

    return 0;

如果我没记错的话,%hhu 代表unsigned char。如果我输入几乎任何字符,如ab,答案是空的,d 得到值0。但如果我输入97,那么d 会打印出a 的值(因此ASCII 会转换为字符)。当数据类型为char 时显然不是这种情况。我可以直接输入字符并存储它。

同样在此代码的轻微修改中

#include <stdio.h>

int main()

    unsigned char c;
    char d;
    int g;
    scanf("%hhu", &d);
    printf("%c\n", d);
    scanf("%d", &g);
    printf("%d is g\n", g);

    return 0;

如果我将第一个输入作为wa 之类的字符,那么它只会跳过第二个scanf,但如果输入是一个数字,那么它可以正常工作。

【问题讨论】:

a 不是%hhu 的有效输入,因此scanf 返回错误。检查scanf返回的值。 Re "这是两个不同的问题",不,只是提供错误数据的两个例子。 【参考方案1】:

%hhu 格式说明符需要 unsigned char* 参数是正确的。但是,格式的u 部分指示输入被解释为十进制整数。要将数据作为(未处理的)字符输入,您应该使用%c 格式说明符。

【讨论】:

【参考方案2】:

格式说明符%u 用于读取十进制整数,%hhu 是添加了长度修饰符的%u

要将一个字符读入char 变量,请使用说明符%c

【讨论】:

【参考方案3】:

如果我输入几乎任何字符,如“a”或“b”,答案是空的,d 得到值 0。但如果我输入 97,则 d 打印值 a。 (所以 ASCII 被转换为 char)当数据类型是 char 时显然不是这种情况。

scanf 所做的与类型无关,而是与您使用的格式说明符有关(反过来,它定义了参数中预期的类型)。

当您使用%hhu 时,输入被读取为有符号十进制整数,解析为strtoul,并存储在unsigned char 中。这就是97 被正确读取的原因。

此外,在这两个示例中,您都应该考虑返回值以了解是否有任何失败。这样您就可以检测错误并执行任何需要的操作,例如再次询问用户。

【讨论】:

【参考方案4】:

a 不是%hhu 的有效输入。需要一个整数(在数学意义上)。如果我们添加错误检查(下面的代码),我们会得到:

$ gcc -Wall -Wextra -pedantic a.c -o a && ./a
a
Number of assigned variables: 0
Can't read: Invalid input
#include <stdio.h>
#include <stdlib.h>

int main(void) 
    unsigned char c;

    int rv = scanf("%hhu", &c);
    if (rv == EOF) 
       if (ferror(stdin)) 
          perror("Can't read");
        else 
          fprintf(stderr, "Can't read: Premature EOF\n");
       

       exit(1);
    

    printf("Number of assigned variables: %d\n", rv);

    if (rv < 1) 
       fprintf(stderr, "Can't read: Invalid input\n");
       exit(1);
    

    printf("%hhu\n", c);

    return 0;


无效输入保留在句柄的缓冲区中,以供将来读取。因此,早期 scanf 中的错误可能会导致后期 scanf 失败。

如果您希望在出现错误后继续,您可以简单地读取,直到获得 LF 以清除缓冲区中的任何“垃圾”。

void read_stdin_to_eol(void) 
   while (1) 
      int ch = getchar();
      if (ch == '\n' || ch == EOF)
         return ch;
   

【讨论】:

为了理解像你解释的那样谈论“句柄缓冲区”的scanf,我可以得到一些来源或指针吗? 只表示不吸收无效输入。未来的读取将从导致错误的字符开始,而不是之后的字符。从我系统上的手册页中不清楚是否会发生这种情况。【参考方案5】:

如果我没记错的话,%hhu 代表unsigned char。如果我输入几乎任何字符,如“a”或“b”,答案是什么,d 的值为 0。

"%hhu" 期望输入文本是数字,如@9​​87654324@。然后将 123 的值保存在d 中。 d 没有得到值 0。d 没有被 scanf("%hhu", &amp;d); 更改,因为输入无效。

如果要将字符读入unsigned char

unsigned char d;
if (scanf("%c", &d) == 1) Success();

如果您想将数字文本读入unsigned char

unsigned char d;
if (scanf("%hhu", &d) == 1) Success();

在所有情况下,测试scanf()的返回值。


如果我将第一个输入作为 'w' 或 'a' 之类的字符给出,那么它只会跳过第二个 scanf,但如果输入是一个数字,那么它会正常工作。

scanf() 未能按照提供的说明符转换输入文本时,扫描停止并且有问题的文本保留stdin 中。

一个常见的代码习惯是读取剩余的输入并将其折腾到'\n'

int ch;
while ((ch = getchar()) != '\n') && ch !- EOF) 
  ;

【讨论】:

以上是关于数据类型为 unsigned char 时 scanf 的行为问题的主要内容,如果未能解决你的问题,请参考以下文章

在C语言中,unsigned char是啥类型

在C语言中,unsigned char是啥类型

char和unsigned char--数据类型区别

在 c语言中int long unsigned 和 char这四种类型数据的转换规律是_____.

unsigned char 与 char 有啥却别?何时适用

char和unsigned char--数据类型区别