为啥 printf 是在本地定义的,而 getchar 是在外部定义的?

Posted

技术标签:

【中文标题】为啥 printf 是在本地定义的,而 getchar 是在外部定义的?【英文标题】:Why is printf defined locally as opposed to getchar, which is defined externally?为什么 printf 是在本地定义的,而 getchar 是在外部定义的? 【发布时间】:2015-12-07 09:58:18 【问题描述】:

当使用带有 MASM(x86 架构)的汇编语言时,可以通过包含库来使用标准 C 函数。例如:printfgetchar

Visual Studio 中使用Asembly With Source Code/FAs 进行编译并检查生成的程序集文件时,我偶然发现了以下内容:

PUBLIC  _printf
EXTRN   __imp__getchar : PROC

_printf 声明为 PUBLIC 并在 本地 定义(inline 在同一文件中,因此不在库文件中外部定义),而 _imp_getchar外部定义

这是编译器在debug 中编译时生成的_printf 定义:

_TEXT   SEGMENT
__ArgList$ = -20                    ; size = 4
__Result$ = -8                      ; size = 4
__Format$ = 8                       ; size = 4
_printf PROC                        ; COMDAT

; 950  : 

push    ebp
mov ebp, esp
sub esp, 216                ; 000000d8H
push    ebx
push    esi
push    edi
lea edi, DWORD PTR [ebp-216]
mov ecx, 54                 ; 00000036H
mov eax, -858993460             ; ccccccccH
rep stosd

; 951  :     int _Result;
; 952  :     va_list _ArgList;
; 953  :     __crt_va_start(_ArgList, _Format);

call    ??$__vcrt_va_start_verify_argument_type@QBD@@YAXXZ ; __vcrt_va_start_verify_argument_type<char const * const>
lea eax, DWORD PTR __Format$[ebp+4]
mov DWORD PTR __ArgList$[ebp], eax

; 954  :     _Result = _vfprintf_l(stdout, _Format, NULL, _ArgList);

mov eax, DWORD PTR __ArgList$[ebp]
push    eax
push    0
mov ecx, DWORD PTR __Format$[ebp]
push    ecx
mov esi, esp
push    1
call    DWORD PTR __imp____acrt_iob_func
add esp, 4
cmp esi, esp
call    __RTC_CheckEsp
push    eax
call    __vfprintf_l
add esp, 16                 ; 00000010H
mov DWORD PTR __Result$[ebp], eax

; 955  :     __crt_va_end(_ArgList);

mov DWORD PTR __ArgList$[ebp], 0

; 956  :     return _Result;

mov eax, DWORD PTR __Result$[ebp]

; 957  : 

pop edi
pop esi
pop ebx
add esp, 216                ; 000000d8H
cmp ebp, esp
call    __RTC_CheckEsp
mov esp, ebp
pop ebp
ret 0
_printf ENDP
_TEXT   ENDS

我的问题

为什么_printf 是在本地定义的,而getchar 是在外部定义的?

【问题讨论】:

因为这是printf本身的来源。 @Jester 这如何以任何方式回答我的问题?这如何解释 getchar 的来源未被复制? 【参考方案1】:

printf 的代码就在您的列表中。如果你删除程序集,你会得到:

; 950  : 
; 951  :     int _Result;
; 952  :     va_list _ArgList;
; 953  :     __crt_va_start(_ArgList, _Format);
; 954  :     _Result = _vfprintf_l(stdout, _Format, NULL, _ArgList);
; 955  :     __crt_va_end(_ArgList);
; 956  :     return _Result;
; 957  : 

所以,printf 是一个(内联?)函数,它调用 _vfprintf_l,它完成了所有繁重的工作(并且可能也用于实现其他 C 库函数)。

【讨论】:

以上是关于为啥 printf 是在本地定义的,而 getchar 是在外部定义的?的主要内容,如果未能解决你的问题,请参考以下文章

诅咒库:为啥 getch() 清除我的屏幕?

为啥我需要两个 _getch() 才能获得正确的值? [复制]

没有头文件,为啥下面的程序能运行

为啥我的图像(本地资产或下载的资产)没有在 iOS 14 上显示,而是在使用 ReactNative 0.62.x 的 Android 上显示?

为啥我的 mvc 项目重定向到默认的 403 错误页面,而不是我重定向到的页面,而不是在本地的 IIS 上?

为啥我们使用 10.0.2.2 连接到本地 Web 服务器而不是在 android 客户端中使用计算机 IP 地址