当编译C程序时,它按照预处理器,编译器,汇编器,链接器的顺序进行.其中一项主要任务linker是为您的程序提供库函数代码.链接器可以通过静态或动态两种方式链接它们.
stdio.h仅包含声明,其中不存在任何定义.我们只stdio.h在程序中包含关于返回类型和函数名称的编译器eg(printf(),scanf(),getc(),putc()...)..
然后怎么printf()和scanf()链接?
总"C"库是否与程序动态链接?
#include"stdio.h"
int main(){int n;
printf("输入一个整数\n"); scanf("%d",&n);
if(n%2 == 0)printf("Even \n"); else printf("Odd \n");
返回0; }
zwo*_*wol 10
我认为你正试图问的问题是:"我知道,像函数printf和scanf由C运行时库中实现.但我可以使用它们而不告诉我的编译器和/或IDE将我的程序与C运行时库链接.为什么我不需要这样做?"
这个问题的答案的问题是:"该程序并不需要与C运行时库链接是非常,非常罕见.即使您没有明确使用任何库函数,您仍然需要启动代码,并且编译器可能会memcpy在"引擎盖下" 发出对浮点仿真函数等的调用.因此,为方便起见,编译器会自动将您的程序与C运行时库链接,除非您告诉它不这样做."
您将不得不查阅编译器的文档,以了解如何告诉它不要在C运行时库中链接.GCC使用-nostdlib命令行选项.下面,我展示你必须跳过的箍才能完成这项工作......
$ cat > test.c
#include <stdio.h>
int main(void) { puts("hello world"); return 0; }
^D
$ gcc -nostdlib test.c && { ./a.out; echo $?; }
/usr/bin/ld: warning: cannot find entry symbol _start
/tmp/cc8svIx5.o: In function ‘main’:
test.c:(.text+0xa): undefined reference to ‘puts’
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
puts显然是在C库中,但这个神秘的"入口符号_start" 也是如此.关闭C库,你必须提供的是自己,太...
$ cat > test.c
int _start(void) { return 0; }
^D
$ gcc -nostdlib test.c && { ./a.out; echo $?; }
Segmentation fault
139
Run Code Online (Sandbox Code Playgroud)
它现在链接,但我们得到一个分段错误,因为_start无处可回!操作系统希望它可以调用_exit.好的,我们这样做......
$ cat > test.c
extern void _exit(int);
void _start(void) { _exit(0); }
^D
$ gcc -nostdlib test.c && { ./a.out; echo $?; }
/tmp/ccuDrMQ9.o: In function `_start':
test.c:(.text+0xa): undefined reference to `_exit'
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
...坚果,_exit也是C运行时库中的一个函数!原始系统通话时间......
$ cat > test.c
#include <unistd.h>
#include <sys/syscall.h>
void _start(void) { syscall(SYS_exit, 0); }
^D
$ gcc -nostdlib test.c && { ./a.out; echo $?; }
/tmp/cchtZnbP.o: In function `_start':
test.c:(.text+0x14): undefined reference to `syscall'
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
......不,syscall是同样在C运行时函数.我想我们只需要使用汇编!
$ cat > test.S
#include <sys/syscall.h>
.text
.globl _start
.type _start, @function
_start:
movq $SYS_exit, %rax
movq $0, %rdi
syscall
$ gcc -nostdlib test.S && { ./a.out; echo $?; }
0
Run Code Online (Sandbox Code Playgroud)
最后,这是有效的.在我的电脑上.它不适用于不同的操作系统,具有不同的系统调用程序集级别约定.
你可能现在想知道什么-nostdlib是好的,如果你不得不下降到汇编语言只是为了进行系统调用.它旨在用于编译完全独立的低级系统程序,如引导程序,内核和C运行时本身(部分) - 无论如何都必须实现自己的一切.
如果我们从头开始重新做一遍,那么分离出一个低级语言无关的运行时,只需要syscall包装器,与语言无关的进程启动代码,以及任何语言编译器可能的函数,这都是有意义的.需要调用("引擎盖下" memcpy,_Unwind_RaiseException,__muldi3,诸如此类的事情).这个想法的问题是它迅速遭受任务蔓延 - 你包括 errno吗?通用线程原语?(哪些是哪种语义?)动态链接器?一个实现malloc,上面的几个东西需要什么?窗口的ntdll.dll开始为这个概念,它是在磁盘上1.8MB在Windows 10,这是(略)更大的比libc.so+ ld.so在我的Linux分区.编写一个仅使用的程序是很少见和困难的ntdll.dll,即使你是微软(我唯一可以肯定的例子csrss.exe,也可能是内核组件).
通常,标准 C 库是动态链接的。这主要是因为一旦程序被静态链接,其中的代码将永远固定。如果有人发现并修复了printf或 中的错误scanf,则必须再次链接每个程序以获取固定代码。
在动态链接的情况下,没有一个可执行文件(链接后创建)包含printf或的代码副本scanf。如果有一个新的、固定的、printf可用的版本,那么它会在运行时被选取。
| 归档时间: |
|
| 查看次数: |
3059 次 |
| 最近记录: |