gcc是一种C编译器,这次我们根据书上的代码尝试着使用它。

使用之前,先补充前置知识。编译器将源代码转换为可执行代码的流程:首先,预处理器对源代码进行处理,将#define指定的宏进行替换,将#include包含的文件插入,随后,编译器生成源文件对应的汇编代码,以.s结尾。然后汇编器会将汇编代码转换为机器代码,以.o结尾,最后,链接器将多个机器代码(如果有多个的话)以及代码中用到的库函数(如printf)合并,产生可执行文件。

若要比较详细地了解gcc常用参数,可以参考这篇文章:

https://www.cnblogs.com/zhangsir6/articles/2956798.html

里面讲得比较详细,当然,如果像我一样想要以书为导向,看到不懂的再学,可以先不看那个,先继续看下面的文章。

为了演示gcc的用法,书中演示了命令行 gcc -Og -o p p1.c p2.c的运行效果,我们需要做下实验:

我使用的是MAC,直接打开终端就可输入命令行来实验了,要注意的是p1.c和p2.c需要自己生成,且这两个文件必须位于当前目录下。

首先用xcode新建个c程序,名为p1.c,里面敲入最简单的代码,如下:

同理,再创建个p2.c,随后将两个文件放到想要测试的目录下,比如我在桌面新建了"测试gcc"文件夹:

打开终端,使用cd指令进入到此目录下(暂时不会linux,先用最简单的方法,打下cd,随后拖动对应目录进终端,会自动把路径导入,如下图)

按回车,进入此目录:

先尝试下

gcc -Og -o p p1.c p2.c  这条指令,会发现居然报错了!结果如下:

因为p1.c和p2.c都有main函数,导致报错了,好,那现在就把p2.c的主函数注释掉吧,如下:

重新执行指令,效果如下:

生成了名为p的可执行文件,可以看到它没有后缀,点开看看有什么惊喜:

看到那个p1.clogout没?那是p1.c的main函数中输出的东西。

至此,书上的代码执行完毕,开始思考。

1.gcc的是区分大小写的,这点自己试试就能发现。

2.-Og(注意,是大写的字母O,不是数字0)代表要求gcc编译器使用符合原始C代码整体结构的机器代码的优化等级,说白了就是编译器在把源代码变成机器语言时会作一定程度的优化,导致产生的机器代码出现了变形。同样的,也有-O1,-O2,-O3,-O4等等优化等级,数字越大优化等级越高。-Og是在gcc 4.8版本引入的,基本相当于没有优化。

3.编译时可以指定文件生成到流程的哪一步,比如-S用来指定生成汇编代码(以.s结尾),-c可以指定生成到机器代码(以.o结尾),若什么都不输入,则默认生成到可执行文件,展示如下:

可以看到,生成的.s以及.o文件默认都是和源文件同名的,可执行文件则默认命名为a.out。

3.-o是用来指定目标名称的,可以在指定名字的时候加上对应的后缀,以生成不同类型的文件,比如hello.exe,hello.asm等,如下图所示:

这里有个疑问,若我不生成可执行文件,只生成.s或者.o文件,但不想用默认的p1.s作为名字,是否能通过-o改呢?另外,改的时候如果没有用.s作后缀名,会怎样呢?下面是结果:

可以看到,不仅仅是可执行文件,即使是.s文件,也是可以用-o的方式改名的。另外,虽然这个时候名字被改变了,乃至后缀都变了,比如那个test,但其实内容和直接生成的p1.s是一样的,可以看到它们的大小都是相同的,用文本编辑器打开会发现内容相同。当然了,为什么test.s和p1.s大小不同就不懂了,试着打开了test.s,结果是乱码。。。难道是生成了机器码嘛?

当然,以上结果对.o文件应该也适用,简便起见就没做测试了。

4.我发现一个奇怪的现象,似乎gcc编译器对语法的检测是有限制的?

现象如下:我先把p1.c里的main函数改个名,如mafin,此时居然能生成.s和.o文件,直到生成可执行文件时才报出错来:

按我以前了解的知识,编译器在编译的时候不应该就直接检测语法错误了吗?为什么生成.s时不报错?难道以前是我记错了,是在链接的时候检测的?

我做了另一个实验,把main改正常,并在main函数里随便打了一串字符,结果如下:

这次倒是对了,生成.s文件的时候肯定进行了语法检测,那只能说明main改成mafin不算语法错误?不可思议,我又尝试把main函数注释掉,加了个函数进去,结果和第一次一样,如下:

.s和.o能直接生成,也是到了生成可执行文件才报错。

好吧,我没有耐心了,后面还有很多东西要看,姑且暂时认为main函数里出了错不算语法错误吧,可能需要学完编译原理才能解释这个现象。

5.还记得当时测试书上的代码时我们同时编译了p1.c和p2.c吗?如果按照那个方式写,编译器会分别对二者生成到.o并链接,最后生成可执行文件,显然,有两个main函数会报错的,那如果我们不生成可执行文件,仅仅是同时生成.s和.o文件,在存在两个main函数的情况下,会报错吗?结果如下:

 

答案是:不会报错,能同时生成。

那么如果同时对两个文件生成.s,且要同时分别命名是否可以呢?结果如下:

根据提示来看,是不支持的,不管你是用gcc -S -o test1 p1.c p2.c还是妄图施展gcc -o test1  -S p1.c -o test2 -S p2.c这样的骚套路,统统都是行不通的。。

当然,gcc的命令参数很多很多,这儿仅仅是基于书上的内容作的一些测试和拓展,想要了解更多请看开头的链接,让我们愉快地结束这一节吧。

(有疑惑的,请看博客的“写在前面”一章)

CSAPP阅读笔记-gcc常用参数初探-来自第三章3.2的笔记-P113的更多相关文章

  1. CSAPP阅读笔记-数组分配与访问-来自第三章3.8的笔记-P176-P183

    这一节比较简单,仅记录几个比较重要的点: 1.C语言允许对指针进行运算,计算出的值会根据该指针引用的数据类型大小进行伸缩. 例子: 其中,xE是数组的起始地址.注意,指针运算时,若最终结果为指针,则指 ...

  2. CSAPP阅读笔记-struct, union, 数据对齐-来自第三章3.9的笔记-P183-P191

    1.数据对齐 为什么要对齐:通俗点解释就是CPU对数据访问时,每次都是取固定数量的字节数,假如一次取4个字节,若有个int存在0x01-0x04,则一次就能取出,若存在0x03-0x06,则需要分两次 ...

  3. CSAPP阅读笔记-汇编语言初探(控制类指令)-来自第三章3.6的笔记-P135-P163

    1.正溢出与负溢出: 首先,一个正数与一个负数相加,不可能溢出,因为结果的绝对值一定小于两个加数的绝对值,既然两个加数能合理表示出来,结果一定也能合理表示出来. 其次,正溢出是由于两个很大的正数相加, ...

  4. CSAPP阅读笔记-汇编语言初探(算术和逻辑操作类指令)-来自第三章3.5的笔记-P128-P135

    1.算术和逻辑操作类指令分四类:加载有效地址,一元操作,二元操作和移位,如下: 2. leaq指令,类似mov指令,它左侧的数看似是给出一个地址,在内存中从给定的地址取操作数,传给右边的目的地.但其实 ...

  5. CSAPP阅读笔记-变长栈帧,缓冲区溢出攻击-来自第三章3.10的笔记-P192-P204

    一.几个关于指针的小知识点: 1.  malloc是在堆上动态分配内存,返回的是void *,使用时会配合显式/隐式类型转换,用完后需要用free手动释放. alloca是标准库函数,可以在栈上分配任 ...

  6. CSAPP阅读笔记-栈帧-来自第三章3.7的笔记-P164-P176

    1.基本结构: 如上图所示,是通用的栈帧结构.大致分两块,调用者函数P和被调用者函数Q. 对P来说,要做的工作是把传递参数中多于6个的部分压栈,随后把Q返回时要执行的下一条指令的地址压栈. 对Q来说, ...

  7. Java程序设计(2021春)——第三章类的重用笔记与思考

    Java程序设计(2021春)--第三章类的重用笔记与思考 本章概览: 3.1 类的继承(概念与语法) 3.2 Object类(在Java继承最顶层的类) 3.3 终结类和终结方法(只能拿来用,不可以 ...

  8. JVM笔记-GC常用参数设置

    GC常用参数 -Xmn -Xms -Xmx -Xss 年轻代 最小堆 最大堆 栈空间, -Xms -Xmx 一般设置成一样大小, -XX:+UseTLAB 使用TLAB,默认打开 -XX:+Print ...

  9. GCC常用参数

    GCC--GNU C Compiler c语言编译器(远不止c语言) 介绍: 作为自由软件的旗舰项目,Richard Stallman 在十多年前刚开始写作 GCC 的时候,还只是把它当作仅仅一个C ...

随机推荐

  1. C#Task学习

    简介: Task 对象是一种的中心思想基于任务的异步模式首次引入.NET Framework 4 中. 因为由执行工作Task对象通常以异步方式执行线程池线程上而不是以同步方式在主应用程序线程中,可以 ...

  2. WPF MultiSelect模式下ListBox 实现多个ListBoxItem拖拽

    WPF 的ListBox不支持很多常见的用户习惯,如在Explorer中用鼠标可以选择多项Item,并且点击已经选择的Item,按住鼠标左键可以将所有已选择Item拖拽到指定的位置.本文简单的实现了这 ...

  3. SQL server 查询语句优先级-摘抄

    SQL 不同于与其他编程语言的最明显特征是处理代码的顺序.在大数编程语言中,代码按编码顺序被处理,但是在SQL语言中,第一个被处理的子句是FROM子句,尽管SELECT语句第一个出现,但是几乎总是最后 ...

  4. 《C#多线程编程实战》2.6 ManualResetEventSlim

    这个比较好理解的. 正如书上所言,如同一直在打开的大门的屋子,谁要进去,谁就自己的关门,出来的时候在开开. 常用的方法 有三个: Set()  //设置为有信号,也就是让等待的线程不用继续等待,唤醒等 ...

  5. [SinGuLaRiTy] 复习模板-数据结构

    [SinGuLaRiTy-1040] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 二维线段树 2D_Segment_Tree //示例:单 ...

  6. Swoole http server + yaf, swoole socket server + protobuf 等小结

    拥抱swoole, 拥抱更好的php Swoole 是什么? Yaf 是什么? 接触swoole已经4年多了,一直没有好好静下心来学习.一直在做web端的应用,对网络协议和常驻内存型服务器一窍不通.一 ...

  7. django-redis 使用规范

    django-redis 基于 BSD 许可, 是一个使 Django 支持 Redis cache/session 后端的全功能组件. 1,安装 django-redis 最简单的方法就是用 pip ...

  8. bzoj1867钉子和小球

    题目链接 简单$DP$ $$dp[1][1]=1(\text{显然})$$ $$map[i][j]=='*'?dp[i+1][j]+=dp[i][j]/2,dp[i+1][j+1]+=dp[i][j] ...

  9. Unity---动画系统学习(1)---在状态机中简单控制物体运动

    1. 介绍 新建一个GameObject-Cube,在Window下添加Animation(快捷键ctrl+6).会添加用于播放动画的三个东西.物体上的Animator组件.Animator Cont ...

  10. WPF强制设置TextBox文本框的焦点

    在需求中遇到这样一种场景:就是在无论何时都要把焦点设置在一个TextBox中. 引用空间:System.Windows.Input 方式1:在窗体的Load事件中去设置焦点,(注意:不能在窗体的构造函 ...