linux下gcc参数的使用以及编译过程

gcc的使用

-v / --v / --version    查看gcc版本号

-I目录  指定头文件目录,注意-I和目录之间没有空格

-c  只编译,生成.o文件,不进行链接

-g  包含调试信息

-On n=1~3 编译优化,n越大优化的越多

-Wall   提示更多告警信息(严格编译)

-D<DEF> 编译时定义宏,注意-D和<DEF>之间没有空格

-E  生成预处理文件,一般是.i文件,(展开头文件,替换宏常量)

-M  生成.c文件与头文件依赖关系以用于Makefile,包括系统库的头文件

-MM 生成.c文件与头文件依赖关系以用于Makefile,不包括系统库的头文件

gcc各项参数的实际说明

目录结构:
.
├── include
│ └── calc.h
├── src
│ └── calc.c
└── test
└── main.c

  • 头文件创建格式 calc.h
#ifndef __CALA_H_
#define __CALA_H_

int add(int a, int b); 
int sub(int a, int b); 
int mul(int a, int b); 
int div(int a, int b); 

#endif
  • 函数库 calc.c
int add(int a, int b)
{
    return a+b;
}
int sub(int a, int b)
{
    return a-b;
}
  • 代码 main.c
#include <stdio.h>
//#include "../include/calc.h"  //第一条
//#include <calc.h>  //第二条
#include <calc.h> //第三条


int main(void)
{
    int a = 4;
    int b = 2;
    printf("%d + %d = %d\n", a, b, add(a,b));

    return 0;
}

-I

  • 使用第一条头文件的时候,gcc的编译命令是gcc main.c ../src/calc.c,通过"../include/calc.h"这段找到头文件并且编译成功
  • 使用第二条头文件的时候,gcc的编译命令是gcc main.c ../src/calc.c -I../include/,一般来说,用<>括起来的头文件是系统头文件,-I../include/这条命令就是把../include/这条目录临时并到系统查找的头文件目录里,来查找头文件
  • 使用第三条头文件的时候,gcc的编译命令还是gcc main.c ../src/calc.c -I../include/

-c

  • gcc命令gcc main.c -I../include/这样的话,会有错误提示
    /tmp/ccQeQFPr.o: In function 'main':
    main.c:(.text+0x29): undefined reference to 'add'
    collect2: ld 返回 1

因为main函数要调用add函数,但是包含add函数的calc.c没有参与编译,造成add函数未定义

  • 但是如果是执行gcc main.c -I../include/ -c这条命令则不会报错,会生成main.o这个文件,.o叫做可重新定位的目标二进制文件,它是不可执行的,它要跟calc.c生成的calc.o链接才会生成a.c的二进制可执行文件。
    gcc main.c ../src/calc.c -I../include -c/同时生成main.o和calc.o

-D

代码

#include <stdio.h>

int main(void)
{
    int a;

    scanf("%d", &a);

#ifdef MYDEBUG
    printf("a = %d\n", a); //调试语句,查看scanf输入的值是多少
#endif

    if(a > 10) 
        printf("num is more than 10\n");
    else
        printf("num is less than 10\n");

    return 0;
}
  • 在编译器进行预处理的时候,如果发现MYDEBUG(这个名字可以随便起)这个宏没有定义,就会无视从#ifdef到#endif之间的代码
    只有定义了这个宏#define MYDEBUG 1,#ifdef到#endif的代码才会执行,MYDEBUG可以不用置换任何常量,#define MYDEBUG 也是可以的。
  • 也可以通过gcc里面的编译参数来定义这个宏,并且这个宏数全局的gcc -DMYDEBUG main.c,这个时候#ifdef到#endif之间的代码也会执行

- 应用场景
在程序研发阶段可以利用-D调试代码,由于调试代码过多,也为了以后进行二次使用这段代码,在不删除调试代码的情况下,生成一个不会出现调试代码的产品,这种方法还是非常便利的。
当然,也可以把MYDEBUG放到头文件定义,但会有像上例中calc.c的文件本来就不必包含头文件的情况下,多少有些多余,但是方法还是可行的。

编译过程

Created with Raphaël 2.1.0 gcc编译过程 hello.c hello.c hello.i hello.i hello.s hello.s hello.o hello.o a.out a.out gcc -E cpp预处理器 gcc -S gcc编译器 gcc -c as汇编器 gcc ld链接器

hello.c->hello.i->hello.s->hello.o->a.out

编译工具链

  • cpp :预处理器(展开头文件,替换宏常量)
  • gcc :编译器,是把.c文件翻译成汇编,gcc -S把.c编译成汇编
  • as :汇编器
  • ld :链接器:1.插入启动代码,2.地址重定位

在.o文件链接之后,还有插入启动代码、地址重定位

实际上,一个程序是从启动代码开始的,启动代码在调用main函数,例如在main里打开一个文件,如果没有关闭,return 0之后,由启动代码把文件关掉,return的值也是返回给启动代码的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值