我正在学习 geeksforgeeks ,当我看到这个时,我想到了一个想法,因为getchar()
和其他类似的函数返回一个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()
printf()
内发生的printf()
显示了什么?
我对C standard library
实现做了一些研究,并了解printf是libc
(又名_update_by_query
)的一部分,是一个可变函数(printf)但是我没有知道这个函数里面真正发生了什么,以及它如何通过格式说明符知道它必须打印字符或int?
请帮助我学习正在进行的整个过程。
答案 0 :(得分:2)
getchar
的手册页说明如下:
fgetc()
从流中读取下一个字符并将其作为一个返回unsigned char
投放到int
或文件结尾或错误的EOF。
getc()
相当于fgetc()
,但它可以实现为 不止一次评估流的宏。
getchar()
相当于getc(stdin)
。
因此,假设您输入了字符A
。假设您的系统使用字符的ASCII表示,则此字符的ASCII值为65.因此,在这种情况下,getchar
将返回65作为int
。
int
返回的getchar
值为65,然后作为第二个参数传递给printf
。 printf
函数首先查看格式字符串并查看%c
格式说明符。 printf
的手册页对%c
:
如果不存在
l
修饰符,则int
参数将转换为unsigned char
,并写出结果字符。
所以printf
将下一个参数读作int
。由于我们传入了值{65的int
,因此它就是它所读取的内容。然后将该值转换为unsigned char
。由于它仍处于该类型的范围内,因此值仍为65. printf
然后打印该值的字符。由于65是字符A
的ASCII值,因此出现字符A
。
答案 1 :(得分:1)
(我假设您的计算机有x86-64处理器并运行Linux)
为什么使用的格式说明符是%c,为什么不是%d(或%i)。
想象一下,相应的参数(printf
)是99(int
)。如果您使用%c
,则会显示字母c
(ASCII代码99)。如果您使用%d
或%i
,那么99
会显示printf
,等等......
printf
是一个可变函数。它是使用variadic primitives实现的,如va_start
和va_end
,它们是扩展到编译器已知的内置函数的宏。在一个名为ABI(calling convention)的文档中,如何传递确切的参数并给出结果(application binary interface)(在某些处理器和操作系统特定的方式中)。
在某些C标准库实现中,printf
(以及相关函数,如vfprintf
)最终会使用putc
或其他相关内容。
请注意,标准I / O函数(<stdio.h>
中的函数)可能在某些operating system的帮助下提供。有关操作系统的更多信息,请阅读Operating Systems : Three Easy Pieces。
通常,C standard library会使用某些system calls与操作系统kernel进行交互。对于Linux,这些列在syscalls(2)中,但请阅读Advanced Linux Programming。要输出一些数据,将使用write(2)系统调用(但C标准库通常是缓冲,请参阅setvbuf(3))。
BTW,对于Linux / x86-64,GNU glibc&amp; musl-libc是free software的C standard library实现,您可以研究它们的源代码(大部分内容都是用C语言编写的,只需要一点点系统调用粘合剂)。 / p>
但我的问题是在整个过程中getchar()和printf()内部实际发生了什么,其中getchar()返回整数,它存储在哪里......?
ABI定义int
返回函数的结果通过寄存器%rax
,getchar
(与其他int
返回函数一样)以这种方式工作。请参阅X86-64 Linux ABI引用的here。
...以及我们输入的字符是如何通过printf()显示的,即printf()内部发生了什么?
在许多软件层之后,当stdout
流被刷新时(例如通过调用fflush(3),\n
换行符或exit(3)时间,包括从main
返回crt0代码),C标准库将使用write(2)系统调用。内核将处理它以显示某些内容(但细节非常复杂,请先阅读tty demystified)。实际上涉及数百万个源代码行(包括内核内部 - 在DRM内部阅读display server,例如X.Org或Wayland - GPU内的一些代码3}} - ,在terminal emulator内。 Linux是免费软件,因此原则上你可以研究所有这些(但这需要超过一生,典型的Linux发行版有大约二十亿行源代码)。另请参阅OSDev wiki,其中提供了一些实用信息,包括native Intel grapĥics(这是当今最原始的图形)。
PS。您需要花费十多年的时间来了解所有细节(我不这么做)。
答案 2 :(得分:1)
要了解您必须阅读default argument promotions。
其中getchar()返回那个存储的整数
C为您处理此事。
我们输入的字符是如何通过
显示的// split by pipe string[] strArray = text.Split('|'); // taking sixth element in resulting array string value = strArray[5].ToString();
printf()
告诉%c
打印一个角色。