一、常用指令
- 查看帮助,指令:gcc –help
- 查看gcc使用版本:gcc –version
- 编译单个c源程序文件(假设c源程序文件名是:demo.c)成可执行文件:gcc –o demo demo.c
- 生成预处理阶段完成的中间文档。预处理就是对宏定义指令如include、define等进行处理,使用-E开关选项,指令样列:gcc –o demo.i –E demo.c(这儿的demo.i就是预处理完成是形成的中间文件)
- 生成汇编代码:gcc –o demo.s –S demo.c (-S开选项,后面的文件可以是c源程序、通过预处理的.i文件)
- 生成Intel指令格式的汇编代码:gcc –o demo.s –S demo.c –masm=intel。Gcc产生的汇编默认格式为at&t
- 生成机器码:gcc –o demo.o –c demo.s(-c选项,后面文件可以是c源程序、通过预处理的.i文件,生成的汇编程序文件.s)
- 编译时指定宏名 gcc –o demo demo.c –D 宏名
- 编译时用c99标准 .如:gcc –o demo demo.c –std=c99
- 编译多个c程序,这儿的c程序:gcc –o demo demo1.c demo.c
-
编译时指定,源文程字符集。建议源文件以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);
}
3)demo1.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.c与demo1.h文件放到.\demo1目录,那么该如何组织代码编译呢?
1)修改demo.c文件,把include"demo1.h"改成include"demo1/demo1.h"
2)编译创建指令改成如下 gcc –o demo demo.c .\demo\demo1.c
5、strict-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 *则不进行命名限制