一些关于C语言的“基础”(一)——编译

大多数人学习C/C++都是从语法什么的开始学习,只学习如何写代码(我最开始也是),但是时间长了之后会发现,对于一些相对底层的实现一无所知,甚至有一些在我看来比较常识性的问题也一知半解。其实很大程度上是因为,像我这种是没有系统学习过计算机的,一些本应该并行的基础课没有上,所以,这个系列,单独讲一讲我所遇到的,以及我认为会遇到的关于C的“基础概念”

C程序编译步骤

C程序的编译四步

C代码编译成可执行程序经过4步:
1)预处理:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法
2)编译:检查语法,将预处理后文件编译生成汇编文件
3)汇编:将汇编文件生成目标文件(二进制文件)
4)链接:C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去

gcc编译过程

上面的四步很多人都没有什么概念,非计算机专业可能只记得编译和链接,下面通过gcc来演示一下每个过程是做什么的。关于gcc的安装,看这里喽

分步编译

预处理:gcc -E hello.c -o hello.i // 只进行预处理
编  译:gcc -S hello.i -o hello.s // 只进行预处理和编译
汇  编:gcc -c hello.s -o hello.o // 只进行预处理、编译和汇编
链  接:gcc    hello.o -o hello   // 指定生成的输出文件名为 file
// 后缀
// .c	C 语言文件
// .i	预处理后的 C 语言文件
// .s	编译后的汇编文件
// .o	编译后的目标文件

下面来演示一下这个过程
首先选择一个c文件
在这里插入图片描述

  1. 预处理 gcc -E 01.c -o 01.i
    在这里插入图片描述
    成功后我们会得到一个.i文件,我们先来看一下原始的.c文件,先不管它实现的功能,看长度他只有47行
    在这里插入图片描述
    但是.i文件有上千行,宏定义、头文件都被展开了,而且可以看到注释掉的代码被删除了
    在这里插入图片描述
  2. 编译 gcc -S 01.i -o 01.s
    在这里插入图片描述
    现在我们得到了一个.s文件,同样用记事本打开,熟悉汇编的会看到,这里有很多汇编的指令
    在这里插入图片描述
  3. 汇编 gcc -c 01.s -o 01.o
    在这里插入图片描述
    打开.o文件,嗯,现在你什么都看不懂了,因为现在是一堆二进制,但是现在我们可以执行了
    在这里插入图片描述
  4. 执行 gcc 01.o -o 01_elf
    生成可执行文件
    在这里插入图片描述
    执行 01_elf
    在这里插入图片描述

一步编译

gcc 01.c -o demo(还是经过:预处理、编译、汇编、链接的过程)
在这里插入图片描述
这样我们会直接得到一个exe直接执行就好,但是注意这种“非法的”exe很容易被杀毒软件干掉(杀毒软件太灵敏也很无奈,白名单都没有,有的时候只能关掉了)
在这里插入图片描述

查找程序所依赖的动态库

说实话,我觉得这个功能真的不要太有用,之后你会遇到很多库,当他因为库连接不上报错的时候,这个真的真的好用
Windows平台下,我们需要安装相应软件(Depends.exe),来实现这一功能。depends是一款可以查看一个exe文件或dll文件需要依赖哪些dll文件的工具,比如我们生产了一个exe程序,显然在我们的开发环境下是可以执行这个exe程序的,但是换一个环境就不见得了,有的时候我们需要安装库来支持代码的实现,但是突然报错不识别函数,基本就是某一个库没有链接上了,所以我们需要知道这个exe程序都依赖哪些动态链接库,以保证程序离开了开发环境还可以正常运行。
这个下载很方便,不用安装直接解压就能用,[官网在这里],(http://www.dependencywalker.com/)
解压之后直接点击exe就行,在应用里面选择相应的exe文件,但是不知道为什么,我每次打开都很卡,唉。后来看到这篇文件,简直提速不知一百倍,推荐给大家
在这里插入图片描述
包括一些报错x64,x86不兼容的问题,dll版本不对的问题都可以用这里软件来查找解决

暂定下一篇讲内存,关于作用域和内存分区,flag立着里,看我什么时候来兑现吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机科学中的一个重要分支,主要研究如何将高级语言转换为机器语言的过程。其中,词法分析器是编译器中的一个重要组成部分,它负责将源代码中的字符序列转换为有意义的单词序列,也就是词法单元。 下面是一个简单的词法分析器的C语言代码示例: ```c #include <stdio.h> #include <ctype.h> #include <string.h> #define MAX_TOKEN_LEN 100 typedef enum { INT, FLOAT, IDENTIFIER, KEYWORD } TokenType; typedef struct { TokenType type; char value[MAX_TOKEN_LEN]; } Token; char *keywords[] = {"if", "else", "while", "for", "int", "float"}; int is_keyword(char *word) { int i; for (i = 0; i < 6; i++) { if (strcmp(word, keywords[i]) == 0) { return 1; } } return 0; } Token get_token() { Token token; char c = getchar(); while (isspace(c)) { c = getchar(); } if (isdigit(c)) { token.type = INT; int i = 0; while (isdigit(c)) { token.value[i++] = c; c = getchar(); } if (c == '.') { token.type = FLOAT; token.value[i++] = c; c = getchar(); while (isdigit(c)) { token.value[i++] = c; c = getchar(); } } token.value[i] = '\0'; ungetc(c, stdin); } else if (isalpha(c) || c == '_') { token.type = IDENTIFIER; int i = 0; while (isalnum(c) || c == '_') { token.value[i++] = c; c = getchar(); } token.value[i] = '\0'; ungetc(c, stdin); if (is_keyword(token.value)) { token.type = KEYWORD; } } else { token.type = c; } return token; } int main() { Token token; do { token = get_token(); switch (token.type) { case INT: printf("INT: %s\n", token.value); break; case FLOAT: printf("FLOAT: %s\n", token.value); break; case IDENTIFIER: printf("IDENTIFIER: %s\n", token.value); break; case KEYWORD: printf("KEYWORD: %s\n", token.value); break; default: printf("%c\n", token.type); break; } } while (token.type != EOF); return 0; } ``` 这个词法分析器可以识别整数、浮点数、标识符和关键字。它通过一个`get_token()`函数来获取下一个词法单元,并根据单元的类型进行相应的处理。在`get_token()`函数中,它会读取输入流中的字符,根据字符的类型来判断当前单元的类型,并将单元的值存储在一个`Token`结构体中返回。在`main()`函数中,它会不断调用`get_token()`函数来获取下一个单元,并根据单元的类型进行相应的输出,直到读取到输入流的结尾。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值