做seo是要先有网站吗,网站模板首页,怎么做监测网站的浏览量,域名注册信息在哪里找到目录 一、Linux编译器-gcc/g1.1 gcc/g 使用方法1.2 程序的翻译过程1.3 链接 -- 动静态链接特点及区别 二、Linux调试器-gdb2.1 背景2.2 使用方法 三、Linux项目自动化构建工具-make/Makefile3.1 背景3.2 原理3.3 项目清理 一、Linux编译器-gcc/g
1.1 gcc/g 使用方法
格式1.1 gcc/g 使用方法1.2 程序的翻译过程1.3 链接 -- 动静态链接特点及区别 二、Linux调试器-gdb2.1 背景2.2 使用方法 三、Linux项目自动化构建工具-make/Makefile3.1 背景3.2 原理3.3 项目清理 一、Linux编译器-gcc/g
1.1 gcc/g 使用方法
格式 gcc [选项] 要编译的文件 [选项] [目标文件]gcc / g安装 sudo yum install -y gcc-c。安装后的编译器默认的版本是较低的我们可以使用选项-stdc99即使用c99标准-stdc11即使用c11的标准来进行版本提升。使用-o选项可以将编译生成的可执行重命名。最后使用./可执行来运行程序。如下 Linux中一个文件要真正的执行1. 有x权限2. 就是一个可执行文件。 很明显文件test.exe满足上述条件
1.2 程序的翻译过程
程序的翻译过程可以说是生成二进制方案的过程具体可以细分为以下几步
预处理
预处理功能主要包括宏定义,文件包含,条件编译,去注释等。 预处理指令是以#号开头的代码行。
实例: gcc -E test.c -o test.i。选项-E该选项的作用是让gcc从现在开始进行程序的翻译预处理完成就停下 选项-o是指目标文件.i文件为已经过预处理的C原始程序。
编译生成汇编:
在这个阶段中gcc 首先要检查代码的规范性、是否有语法错误等以确定代码的实际要做的工作在检查无误后gcc把c语言代码翻译成汇编语言。
实例: gcc -S test.i -o test.s。用户可以使用-S选项来进行查看该选项的作用是让gcc从现在开始进行程序的翻译编译完成就停下 可以从test.c开始编译也可以从test.i开始。
汇编生成机器可识别代码
汇编阶段是把编译阶段生成的.s文件转成目标文件即将汇编语言编译成为二进制目标文件
实例: gcc -c test.s -o test.o。读者在此可使用选项-c该选项的作用是让gcc从现在开始进行程序的翻译汇编完成就停下。就可看到汇编代码已转化为.o的二进制目标代码了。
链接生成可执行文件或库文件:
实例: gcc hello.o –o hello。在成功编译之后就进入了链接阶段最后形成可执行程序。 那么为什么会有这些过程呢
这就要说到编程语言的历史了。最初的计算机只能处理二进制二进制是处理器的“母语”。这叫“机器语言”或者“机器码”。在计算机早期阶段必须用机器码写程序即二进制编程前段时间很火的《三体1》中早期叶文洁当时就是使用的二进制编程还用到了打孔带上面记录的就是二进制信息。
在1940-1950年代程序员开发一种新语言汇编语言它为每个操作码分配一个简单名字叫“助记符”助记符后面紧跟数据形成完整指令。当然计算机并不认识助记符它只认得二进制码然后就有了汇编的编译器它可以读懂文字指令自动转换成二进制指令这种程序叫“汇编器”
汇编语言直接对应机器码虽然已经很方便了。但是汇编器仍然强迫程序员思考用什么寄存器和内存地址如果我们突然要用额外一个数可能要改很多代码。这时候就出现了一些高级语言和与之对应的编译器如CCJava…。
因为计算机只认识二进制。以c语言为例所以我们要先将c语言代码转化为汇编代码然后再转为二进制目标文件。 那为什么不直接将c语言转为二进制目标文件呢因为前人已经写好了汇编的编译器我们只需站在巨人的肩膀上再将高级语言转为较简单的汇编代码即可。
那么如何形成第一个汇编写的汇编编译器呢 先用二进制写一个汇编编译器此时汇编代码便可通过此编译器形成软件。汇编编译器本质上就是软件那么便可先用汇编语言写一个新的编译器再将这个新的编译器放在二进制写的汇编编译器上执行最后形成新的汇编编译器(软件)。日后只需维护汇编代码即可 这个过程也可叫做编译器的自举(bootstrap)c语言的第一个编译器也是如此形成的
1.3 链接 – 动静态链接特点及区别
我们的C程序中并没有定义printf的函数实现且在预编译中包含的stdio.h中也只有该函数的声明而没有定义函数的实现那么是在哪里实printf函数的呢?
最后的答案是系统把这些函数实现都被做到名为 libc.so.6的库文件中去了在没有特别指定时gcc会到系统默认的搜索路径 /usr/lib下进行查找也就是链接到 libc.so.6库函数中去,这样就能实现函数printf了而这也就是链接的作用。
函数库一般分为静态库和动态库两种。
静态库是指编译链接时把库文件的代码全部加入到可执行文件中因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为.a动态库与之相反在编译链接时并没有把库文件的代码加入到可执行文件中而是在程序执行时由运行时链接文件加载库这样可以节省系统的开销。动态库一般后缀名为.so如前面所述的 libc.so.6就是动态库。gcc在编译时默认使用动态库。完成了链接之后gcc就可以生成可执行文件如下所示。 gcc test.o –o testgcc默认生成的二进制程序是动态链接的这点可以通过 file命令验证。
验证
-static指令作用是链接时使用静态链接 2. ldd 可执行指令作用是查看链接的库 file filename指令查看链接属性 动态库 动态链接的优缺点1. 不能丢失。共享动态库但是一旦动态库缺失所有的动态链接这个库的程序都无法执行 2. 节省资源。
静态库 静态链接的优缺点1. 一旦形成与库无关。在编译的时候把库中的方法拷贝到我自己的可执行程序中此时程序将不再关心任何的库 2. 浪费资源占用空间大。
二、Linux调试器-gdb
2.1 背景
程序的发布方式有两种debug模式和release模式。Linux gcc/g出来的二进制程序默认是release模式。 要使用gdb调试必须在源代码生成二进制程序的时候加上 -g选项此时编译器形成可执行程序的时候会给可执行程序添加调试信息。 我们也可以发现可调式的可执行程序比普通的程序占用内存大。 调试信息大致如下 2.2 使用方法
gdb binFile退出 ctrl d或 quit调试命令
listl 行号 显示binFile源代码接着上次的位置往下列每次列10行。listl 函数名 列出某个函数的源代码。r或run 运行程序对比VS F5。n 或 next 单条执行逐过程对比VS F10。s或step 进入函数调用逐语句对比VS F11。break(b) 行号 在某一行设置断点。break 函数名 在某个函数开头设置断点。info break 查看断点信息。finish 执行到当前函数返回然后停下来等待命令。print() 打印表达式的值通过表达式可以修改变量的值或者调用函数。p 变量 打印变量值。set var 修改变量的值。continue(或c) 从当前位置开始连续而非单步执行程序。delete breakpoints(b) 删除所有断点。delete breakpoints((b) n 删除序号为n的断点。disable breakpoints(b) 禁用断点。enable breakpoints(b) 启用断点。info(或i) breakpoints(b) 参看当前设置了哪些断点。display 变量名 跟踪查看一个变量每次停下来都显示它的值。undisplay 取消对先前设置的那些变量的跟踪。until X行号 跳至X行。breaktrace(或bt) 查看各级函数调用及参数。infoi) locals 查看当前栈帧局部变量的值。quit 退出gdb。
三、Linux项目自动化构建工具-make/Makefile
3.1 背景
会不会写makefile从一个侧面说明了一个人是否具备完成大型工程的能力一个工程中的源文件不计数其按类型、功能、模块分别放在若干个目录中makefile定义了一系列的规则来指定哪些文件需要先编译哪些文件需要后编译哪些文件需要重新编译甚至于进行更复杂的功能操作makefile带来的好处就是——“自动化编译”一旦写好只需要一个make命令整个工程完全自动编译极大的提高了软件开发的效率make是一个命令工具是一个解释makefile中指令的命令工具一般来说大多数的IDE都有这个命令比如Delphi的makeVisual C的nmakeLinux下GNU的make。可见makefile都成为了一种在工程方面的编译方法make是一条命令makefile是一个文件两个搭配使用完成项目自动化构建。
3.2 原理
make是如何工作的在默认的方式下也就是我们只输入make命令。那么
make会在当前目录下找名字叫Makefile或makefile的文件。如果找到它会找文件中的第一个目标文件target在上面的例子中他会找到code.exe这个文件并把这个文件作为最终的目标文件。如果code.exe文件不存在或是code.exe所依赖的后面的code.o文件的文件修改时间要比code.exe这个文件新可以用 touch测试 - 前面讲过touch可以修改文件最近一次被修改的时间那么他就会执行后面所定义的命令来生成code.exe这个文件。如果code.exe所依赖的code.o文件不存在那么make会在当前文件中找目标为code.o文件的依赖性如果找到则再根据那一个规则生成code.o文件。这有点像一个堆栈的过程当然你的C文件和H文件是存在的啦于是make会生成 code.o文件然后再用 code.o文件声明make的终极任务也就是执行文件code.exe了。这就是整个make的依赖性make会一层又一层地去找文件的依赖关系直到最终编译出第一个目标文件。在找寻的过程中如果出现错误比如最后被依赖的文件找不到那么make就会直接退出并报错而对于所定义的命令的错误或是编译不成功make根本不理。make只管文件的依赖性即如果在我找了依赖关系之后冒号后面的文件还是不在那么对不起我就不工作啦。
makefile / make会自动根据文件中的依赖关系进行自动推导帮助我们执行所有的相关的依赖方法。 makefile文件中保存了编译器和链接器的参数选项并且描述了所有源文件之间的关系。make程序会读取makefile文件中的数据然后根据规则调用编译器汇编器链接器产生最后的输出。Makefile里主要包含了五个东西显式规则、隐晦规则、变量定义、文件指示和注释。1. 显式规则说明了如何生成一个或多个目标文件。2. make有自动推导的功能所以 隐晦规则可以让我们比较粗糙地简略地书写makefile 比如源文件与目标文件之间的时间关系判断之类。3. 在makefile中可以定义变量当makefile被执行时其中的变量都会被扩展到相应的引用位置上。4. 通常使用 $(var) 表示引用变量文件指示。包含在一个makefile中引用另一个makefile类似C语言中的include。5. 注释makefile中可以 使用 # 在行首表示行注释。默认的情况下make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件
3.3 项目清理
工程是需要被清理的像clean这种没有被第一个目标文件直接或间接关联那么它后面所定义的命令将不会被自动执行不过我们可以显示要make执行。 即命令——“make clean”以此来清除所有的目标文件以便重编译。但是一般我们这种clean的目标文件我们将它设置为伪目标用.PHONY 修饰伪目标的特性是总是被执行的。 makefile中的伪对象表示对象名称并不代表真正的文件名与实际存在的同名文件没有相互关系因此伪对象不管同名目标文件是否存在都会执行对应的生成指令。伪对象的作用有两个1. 使目标对象无论如何都要重新生成。2. 并不生成目标文件而是为了执行一些指令. 于是我们便可使用vim编写如上内容。里面$相当于取值操作最终会被替换目标文件而^会被替换为依赖方法。