为什么 %c 格式说明符在以下代码中不起作用?

Why does %c format specifier not work in the following code?

我刚刚开始阅读有关 C 的内容,目前正在研究格式说明符。 这是代码示例:

#include <stdio.h>


int main(void) {
    char code = 'a' - 'A';
    printf("\n>>>%c (%d)", code, code);
    printf("\n>>>%c", 32);

    char incode;
    printf("\n\nGive me some char: ");
    scanf("%c", &incode);
    printf("\n>>>%c (%d)", incode, incode);
    return 0;
}

输出:

PS C:\ex> ./print

>>>  (32)
>>>

Give me some char: A

>>>A (65)

那么,为什么%c在最后printf起作用而在开始却不起作用? 我在 Windows 和 Linux 上测试了这个示例,两者的行为相同。

ASCII 32 是 ' ' (space)。印的还行,就是看不出来
如果将格式字符串更改为 "\n>>>%c<< (%d)",您将在(双关语)否定 space.
中看到它 也可以通过od -a输出来确认。

假设你的字符编码是ASCII。那么a编码为97(十进制),A编码为65(十进制)。它们的区别是 32,它编码 space 字符。

所以char code = 'a' - 'A';等同于char code = 32;也就是声明char code = ' ';

另请参阅 this C reference 网站。

如果允许,使用所有警告和调试信息进行编译,因此(使用 GCC)如 gcc -Wall -Wextra -g

您可以使用 gcc -Wall -O -fverbose-asm minerals.c -S -o minerals.s 编译您的 C 源代码 minerals.c 并查看生成的汇编代码 foo.s。在装有 GCC 10.2 的 Debian 计算机上,我收到以下警告:

minerals.c: In function ‘main’:
minerals.c:11:5: warning: ignoring return value of ‘scanf’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
   11 |     scanf("%c", &incode);
      |     ^~~~~~~~~~~~~~~~~~~~

生成的汇编代码有:

 # /usr/include/x86_64-linux-gnu/bits/stdio2.h:107:   return __printf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
         movl    , %ecx       #,
         movl    , %edx       #,
         leaq    .LC0(%rip), %rsi        #,
         movl    , %edi        #,
         call    __printf_chk@PLT        #
         movl    , %edx       #,           // 32 is the space
         leaq    .LC1(%rip), %rsi        #,
         movl    , %edi        #,
         movl    [=11=], %eax        #,
         call    __printf_chk@PLT        #
         leaq    .LC2(%rip), %rsi        #,
         movl    , %edi        #,
         movl    [=11=], %eax        #,
         call    __printf_chk@PLT        #

实际上,在 2021 年,UTF-8 is used everywhere (and complicates matter). Look into GNU libunistring