GCC编译器使用

一、常用指令

  1. 查看帮助,指令:gcc –help
  2. 查看gcc使用版本:gcc –version
  3. 编译单个c源程序文件(假设c源程序文件名是:demo.c)成可执行文件:gcc –o demo demo.c
  4. 生成预处理阶段完成的中间文档。预处理就是对宏定义指令如includedefine等进行处理,使用-E开关选项,指令样列:gcc –o demo.i –E demo.c(这儿的demo.i就是预处理完成是形成的中间文件)
  5. 生成汇编代码:gcc –o demo.s –S demo.c (-S开选项,后面的文件可以是c源程序、通过预处理的.i文件)
  6. 生成Intel指令格式的汇编代码:gcc –o demo.s –S demo.c –masm=intelGcc产生的汇编默认格式为at&t
  7. 生成机器码:gcc –o demo.o –c demo.s(-c选项,后面文件可以是c源程序、通过预处理的.i文件,生成的汇编程序文件.s)
  8. 编译时指定宏名 gcc –o demo demo.c –D 宏名
  9. 编译时用c99标准 .如:gcc –o demo demo.c –std=c99
  10. 编译多个c程序,这儿的c程序:gcc –o demo demo1.c demo.c
  11. 编译时指定,源文程字符集。建议源文件以utf-8的格式保存。这些在处理中文宽字符串时或其他语言的宽字符串时相对容易点。如把源程序当作GB18030格式。增加编译开头选项如下:-finput-charset=GB18030

    1)假设demo1.c源码为:

    #include <stdio.h>

    void printName(char *name);

    void printName(char *name){

        printf("您的姓名是:%s\n",name);

    }

       

    2)假设demo.c源码为

    #include<stdio.h>

    #include"demo1.h"

    void printArray();

    int main(){

    printf("hello world\n");

    printf("你好\n");

    printArray();

    char * name;

    printf("请录入您的姓名:");

    scanf("%s",name);

    printName(name);

    return 0;

    }

    void printArray(){

        char strArray[]={"中国人民站起来了\n"};

        printf("%s",strArray);

    }

    3demo1.h源码为

    void printName(char *name);

    4)注意事项:源码文件只有一个文件含main函数,不能有多个main函数在源码文件中,各个源文件的引用是引用其对应的.h文件。当然也可以直接include"源码文件名.c",如果是这样做,该文件没有必要出现编译列表文件中去。如上面的文件demo.c假设其include"demo1.h"改成include"demo1.c",则gcc编译指令为:gcc –o demo demo.c,写成gcc-o demo demo.c demo1.c则会报错。

二、gcc编译阶段,及产生的文件.gcc分为四个阶段,可以用指令生成任何阶段的文件。

阶段

任务

指令样例

预处理阶段

在预处理阶段,输入的是C语言的源文件,通常为*.c。它们通常带有.h之类头文件的包含文件。这个阶段主要处理源文件中的#ifdef#include#define命令。该阶段会生成一个中间文件*.i

gcc –o demo.i –E demo.c

编译

在编译阶段,输入的是中间文件*.i,编译后生成汇编语言文件*.s

gcc –o demo.s –S demo.i

汇编

在汇编阶段,将输入的汇编文件*.s转换成机器语言*.o

gcc –o demo.o –c demo.s

连接

在连接阶段将输入的机器代码文件*.o(与其它的机器代码文件和库文件)汇集成一个可执行的二进制代码文件

gcc –o demo demo.o

   

三、gcc进阶功能

1、启用编译器警告,显示警告信息,一般是在gcc指令中加选项 –Wall.test.c源代码如下:

#include<stdio.h>

main(){

    int a;

    printf("hello world");

}

这个代码写得有点不符合c标准,如main 函数没有指定int返回类型,变量a没有被使用。可以通过指令控制其是否输出警告信息:

指令:gcc –o test test.c –Wall

输出警告信息如下:

test.c:2:1: warning: return type defaults to 'int'

test.c: In function 'main':

test.c:3:6: warning: unused variable 'a'

test.c:5:1: warning: control reaches end of non-void function

2、把编译器警告当作错误,开关选项是 –Wall –Werror(注意这两个开关要一起用,不用-Wall会看不到提示信息)

样例:

gcc –o test test.c –Wall –Werror

输出如下:

cc1.exe: warnings being treated as errors

test.c:2:1: error: return type defaults to 'int'

test.c: In function 'main':

test.c:3:6: error: unused variable 'a'

test.c:5:1: error: control reaches end of non-void function

3、检查代码是否符合标准C规范,开关选项是-pedantic.

test.c源代码为:

#include<stdio.h>

main(){

    long long int a;

    printf("hello world");

}

使用编译指令如下:

gcc –o test test.c –pedantic

输出结果如下:

test.c: In function 'main':

test.c:3:7: warning: ISO C90 does not support 'long long'

4、编译源代码不在同一个目录下的多个源码文件。实际工程中,为了便于组织代码,不会把所有的源代码都放在同一个目录。

如一大点的7小点,我们可以把demo1.cdemo1.h文件放到.\demo1目录,那么该如何组织代码编译呢?

1)修改demo.c文件,把include"demo1.h"改成include"demo1/demo1.h"

2)编译创建指令改成如下 gcc –o demo demo.c .\demo\demo1.c

5strict-alising 规则

该规则主要是针对不同类型的指针转换,c的指针是强大,如果一个指向int的对象通过类型强制转换指向double,如代码:int *ptr=&abc; double * dptr=(double *)ptr。那么这种转换可能会失败,因为int对象一般在内存中是按4个字节对齐而double对象一般是按8字节对齐。因为存在失败gcc编译器会提出相关警告,在优化选项用-O2及以上。关闭这个选项用-fno-strict-aliasing则可了。

strict-aliasing原解:

Allows the compiler to assume the strictest aliasing rules applicable to the language being compiled.  For C (and C++), this activates optimizations based on the type of expressions.  In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same.  For example, an "unsigned int" can alias an "int", but not a "void*" or a "double".  A character type may alias any other type.

意思是:这个规则不允许不同类型的变量指向同一个地址,除非这变量的类型几乎相等。如unsinged int *可以别名int *。但是unsigned不能别名void *,不能别名 double *。但是char *可以别名任何类型,因为他是1字节对齐呀。什么类型转换给这个char *几乎要改变提指针地址。

如下这段代码:

1 #include<stdio.h>

2

3 void test(unsigned int * unt);

4 void test1(double *dbl);

5 int main(void){

6 int a;

7 a=33;

8 test((unsigned int*)&a);

9 test1((double *)&a);

10 printf("ptr's value is %d\n",a);

11 return 0;

12 }

13 void test(unsigned int * unt){

14 printf("test unsigned value %u\n",*unt);

15

16 }

17 void test1(double *dbl){

18 printf("test double value %f\n",*dbl);

19 }

进行编译时有以下提示:

tsq# gcc stricalias2.c -o stricalias2 -Wall -O2

stricalias2.c: In function 'main':

stricalias2.c:9: warning: dereferencing type-punned pointer will break strict-aliasing rules

意思是不同类型指向同一个地址将打破严格的strict-aliasing这个规则。主要是第9 int *double *这个转换,但是int * unsigned int *则不进行命名限制

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值