计算机系统基础
前言
一、C语言拾遗:机制?
在IDE里,为什么按一个键,就能编译运行?
-
编译、链接
.c ->预编译(gcc -E)->.i>编译(gcc -S) ->.s->汇编 (gcc -c)->.o->链接->a.out
-
加载运行
./a.out
背后是通过调用命令行工具完成的
- RTFM:gcc --help;man gcc
- 控制行为的三个选项:-E,-S,-c
本次课程
- 预热:编译、链接、加载到底做了什么?
- RTFSC时需要关注的c语言特性
输入命令:
命令 | 作用 |
---|---|
cd /Desktop | 转到桌面目录 |
mkdir ics2020 | 新建一个文件夹ics2020 |
cd ics2020 | 进入ics2020目录 |
touch a.c | 新建一个a.c文件 |
vim a.c 编辑a.c | (1)按键i 进入编辑模式 输入 int main(){}(2)按esc 然后输入:wq保存退出 |
gcc a.c | 编译a.c文件生成可执行文件a.out |
./a.out | 执行可执行文件 |
echo $? | 查看上次函数执行的返回结果 |
vim a.out | 编辑可执行文件,可以查看出ELF说明是可执行文件 |
在其中点击esc键,然后输入:%!xxd可以将01转为16进制的文件
命令 | 作用 |
---|---|
file a.out | 查看文件的详细信息 |
gcc --help | 可以查看gcc的文档 |
tldr gcc | 可以查看gcc的简易命令 |
objdump -d 二进制文件 | 反汇编 |
ELF代表可执行文件
进入C语言之前:预编译
#include 文件:就是将文件原样复制到这个位置
通过gcc a.out --verbose 打印出编译连接时的详细信息
下述显示出了gcc可以编译成很多版本的二进制文件,以及当前gcc的版本
如果将“” 写成<>则其默认会去指定目录下寻找该文件,找不到就报错
所以将其通过 -I.的命令,将当前目录添加到<>指定目录列表下,那么就能编译成功
输入命令:gcc a.c -I. --verbose 可以发现
.被加入到了<>的查看目录下面
有趣的预编译
输出yes 因为在当前环境里面宏定义aa和bb都没有被定义,所以等号成立(在预编译里面,可以出现未被定义的宏,因为本质是字符串替换,如果没有宏可以替换,那么就是未被定义)
如下输出的就是no
宏定义与展开
注意在c语言中,宏定义两个字符会自动进行拼接:比如
“##”在宏定义里面用于连接两个字符 比如sys ## tem 就是system
__like__
”代表当前的行号 重定义true
#define SYSTEM sys ## tem
#define true (__like %2 !=0
可以简化程序书写
下面的程序就是打印出hello Tome hello Jerry。。。
编译、汇编、链接
编译 (将c语言转为汇编)
汇编(将汇编转为二进制)
链接(将两个文件链接到一起)
C语言执行的两个视角
内存可以看成一块连续的数组
c语言的一切都是指针
void * p:代表地址 int *p:除了代表地址,还说明了指针指向读取的类型
不论是int * 还是****,不论有多少个*,都是地址
编程理解指针的实际用法
总结
上面将来程序里的一些过程,预处理,编译,汇编,链接,执行