getchar() 和 printf() 内部到底发生了什么?解释整个过程
What's really happening inside getchar() and printf()? Explain whole process
我正在向 geeksforgeeks 学习,当我看到这个时,我想到了 getchar()
和其他类似的功能 returns 一个 int(无论是由于程序失败还是 EOF)那么为什么使用的格式说明符是 %c
,为什么不是 %d(or %i)
.
// Example for getchar() in C
#include <stdio.h>
int main()
{
printf("%c", getchar());
return 0;
}
我知道我们输入的字符是一个字符,它被函数getchar()
获取,我们使用%c
显示它。
但我的问题是在整个过程中 getchar()
和 printf()
内部实际发生了什么,其中 getchar()
返回那个整数,它被存储在哪里以及我们如何处理字符输入的内容由 printf()
i.e.what 在 printf()
?
中显示
我对 printf()
实现做了一些研究,了解到 printf 是 C standard library
(a.k.a. libc
) 的一部分,并且是一个可变参数函数(printf) 但我不知道这个函数内部到底发生了什么,以及它如何通过格式说明符知道它必须打印字符或整数?
请帮助我了解正在进行的整个详细过程。
(我假设您的计算机具有 x86-64 处理器并运行 Linux)
why format specifier used is %c, why not %d(or %i).
假设对应的参数(printf
)是 99(int
)。如果您使用 %c
,则会显示字母 c
(ASCII 代码 99)。如果您使用 %d
或 %i
,则 99
会显示为 printf
,等等...
正如您所注意到的,printf
是一个可变参数函数。它是使用 variadic primitives like va_start
and va_end
which are macros expanded to some builtin known to the compiler. How exactly arguments are passed and results are given (the calling convention) is defined (in some processor & OS specific way) in a document called ABI (application binary interface).
实现的
在某些 C 标准库实现中,printf
(以及相关函数,如 vfprintf
)最终会使用 putc
或相关的东西。
请注意,标准 I/O 函数(<stdio.h>
中的函数)可能会在一些 operating system. Read Operating Systems : Three Easy Pieces 的帮助下提供,以获取更多关于操作系统的信息。
经常 C standard library will use some system calls to interact with the operating system kernel. For Linux these are listed in syscalls(2), but read Advanced Linux Programming. To output some data the write(2) syscall would be used (but the C standard library is generally buffering, see setvbuf(3)).
顺便说一句,对于 Linux/x86-64 和 GNU glibc & musl-libc are free software implementations of the C standard library,你可以研究它们的源代码(大部分是用 C 编写的,有一小部分用于系统调用胶水的汇编)。
But my problem is what's actually happening inside getchar() and printf() during the whole process, where getchar() is returning that integer, where it is getting stored ...?
ABI 定义 int
returning 函数的结果通过寄存器 %rax
和 getchar
(就像其他所有 int
return function) 就是这样工作的。见 X86-64 Linux ABI referenced here.
... and how the character we inputted is getting displayed by printf() i.e. what's happening inside printf()?
在许多软件层之后,当 stdout
流被刷新时(例如通过调用 fflush(3), by a \n
newline character, or at exit(3) time, including returning from main
into crt0 code), the C standard library will use the write(2) syscall. The kernel will process it to show something (But details are horribly complex, read first the tty demystified). Actually millions of source code lines are involved (including inside the kernel - read about DRM, inside the display server such as X.Org or Wayland - also some code inside the GPU -, inside the terminal emulator). Linux is free software, so in principle you can study all of it (but that needs more than a lifetime, a typical Linux distribution has about twenty billions lines of source code). See also OSDev wiki which gives some practical information, including about native Intel grapĥics(这是当今最原始的图形)。
PS。你需要花十多年的时间去了解所有的细节(而我没有)。
要理解你必须阅读 。
where getchar() is returning that integer, where it is getting stored
我帮你处理。
how the character we inputted is getting displayed by printf()
%c
告诉 printf()
打印一个字符。
getchar
的手册页说明如下:
fgetc()
reads the next character from stream and returns it as an
unsigned char
cast to an int
, or EOF on end of file or error.
getc()
is equivalent to fgetc()
except that it may be implemented as a
macro which evaluates stream more than once.
getchar()
is equivalent to getc(stdin)
.
假设您输入了字符 A
。假设您的系统使用字符的 ASCII 表示,该字符的 ASCII 值为 65。因此在这种情况下 getchar
returns 65 作为 int
.
getchar
返回的 int
值 65 然后作为第二个参数传递给 printf
。 printf
函数首先查看格式字符串并查看 %c
格式说明符。 printf
的手册页说明了以下关于 %c
的内容:
If no l
modifier is present, the int
argument is converted to an
unsigned char
, and the resulting character is written.
因此 printf
将下一个参数读取为 int
。因为我们传入了一个值为 65 的 int
,所以它就是这样读的。然后将该值转换为 unsigned char
。由于它仍然处于该类型的范围内,因此该值仍然是 65。 printf
然后打印该值的字符。由于 65 是字符 A
的 ASCII 值,因此字符 A
就是出现的内容。
我正在向 geeksforgeeks 学习,当我看到这个时,我想到了 getchar()
和其他类似的功能 returns 一个 int(无论是由于程序失败还是 EOF)那么为什么使用的格式说明符是 %c
,为什么不是 %d(or %i)
.
// Example for getchar() in C
#include <stdio.h>
int main()
{
printf("%c", getchar());
return 0;
}
我知道我们输入的字符是一个字符,它被函数getchar()
获取,我们使用%c
显示它。
但我的问题是在整个过程中 getchar()
和 printf()
内部实际发生了什么,其中 getchar()
返回那个整数,它被存储在哪里以及我们如何处理字符输入的内容由 printf()
i.e.what 在 printf()
?
我对 printf()
实现做了一些研究,了解到 printf 是 C standard library
(a.k.a. libc
) 的一部分,并且是一个可变参数函数(printf) 但我不知道这个函数内部到底发生了什么,以及它如何通过格式说明符知道它必须打印字符或整数?
请帮助我了解正在进行的整个详细过程。
(我假设您的计算机具有 x86-64 处理器并运行 Linux)
why format specifier used is %c, why not %d(or %i).
假设对应的参数(printf
)是 99(int
)。如果您使用 %c
,则会显示字母 c
(ASCII 代码 99)。如果您使用 %d
或 %i
,则 99
会显示为 printf
,等等...
printf
是一个可变参数函数。它是使用 variadic primitives like va_start
and va_end
which are macros expanded to some builtin known to the compiler. How exactly arguments are passed and results are given (the calling convention) is defined (in some processor & OS specific way) in a document called ABI (application binary interface).
在某些 C 标准库实现中,printf
(以及相关函数,如 vfprintf
)最终会使用 putc
或相关的东西。
请注意,标准 I/O 函数(<stdio.h>
中的函数)可能会在一些 operating system. Read Operating Systems : Three Easy Pieces 的帮助下提供,以获取更多关于操作系统的信息。
经常 C standard library will use some system calls to interact with the operating system kernel. For Linux these are listed in syscalls(2), but read Advanced Linux Programming. To output some data the write(2) syscall would be used (but the C standard library is generally buffering, see setvbuf(3)).
顺便说一句,对于 Linux/x86-64 和 GNU glibc & musl-libc are free software implementations of the C standard library,你可以研究它们的源代码(大部分是用 C 编写的,有一小部分用于系统调用胶水的汇编)。
But my problem is what's actually happening inside getchar() and printf() during the whole process, where getchar() is returning that integer, where it is getting stored ...?
ABI 定义 int
returning 函数的结果通过寄存器 %rax
和 getchar
(就像其他所有 int
return function) 就是这样工作的。见 X86-64 Linux ABI referenced here.
... and how the character we inputted is getting displayed by printf() i.e. what's happening inside printf()?
在许多软件层之后,当 stdout
流被刷新时(例如通过调用 fflush(3), by a \n
newline character, or at exit(3) time, including returning from main
into crt0 code), the C standard library will use the write(2) syscall. The kernel will process it to show something (But details are horribly complex, read first the tty demystified). Actually millions of source code lines are involved (including inside the kernel - read about DRM, inside the display server such as X.Org or Wayland - also some code inside the GPU -, inside the terminal emulator). Linux is free software, so in principle you can study all of it (but that needs more than a lifetime, a typical Linux distribution has about twenty billions lines of source code). See also OSDev wiki which gives some practical information, including about native Intel grapĥics(这是当今最原始的图形)。
PS。你需要花十多年的时间去了解所有的细节(而我没有)。
要理解你必须阅读
where getchar() is returning that integer, where it is getting stored
我帮你处理。
how the character we inputted is getting displayed by
printf()
%c
告诉 printf()
打印一个字符。
getchar
的手册页说明如下:
fgetc()
reads the next character from stream and returns it as anunsigned char
cast to anint
, or EOF on end of file or error.
getc()
is equivalent tofgetc()
except that it may be implemented as a macro which evaluates stream more than once.
getchar()
is equivalent togetc(stdin)
.
假设您输入了字符 A
。假设您的系统使用字符的 ASCII 表示,该字符的 ASCII 值为 65。因此在这种情况下 getchar
returns 65 作为 int
.
getchar
返回的 int
值 65 然后作为第二个参数传递给 printf
。 printf
函数首先查看格式字符串并查看 %c
格式说明符。 printf
的手册页说明了以下关于 %c
的内容:
If no
l
modifier is present, theint
argument is converted to anunsigned char
, and the resulting character is written.
因此 printf
将下一个参数读取为 int
。因为我们传入了一个值为 65 的 int
,所以它就是这样读的。然后将该值转换为 unsigned char
。由于它仍然处于该类型的范围内,因此该值仍然是 65。 printf
然后打印该值的字符。由于 65 是字符 A
的 ASCII 值,因此字符 A
就是出现的内容。