这里写目录标题
一、GCC编译
gcc 编译器
gcc编译C程序时有4个步骤:
1 预处理,针对所有的指令(即以#开头),替换为纯C语法。(-E 生成.i文件)
2 编译(-S 生成.S文件)
3 汇编(高级语言转为汇编,汇编转为机器码)(-c 生成.o文件)
4 链接(.o文件链接)
通常境况下,把预处理、编译和汇编统称为编译(广义)
gcc -E 只做预处理,不做其他的。
gcc -E hallo.c -o hallo.i则生成.i文件
gcc -c 编译但不链接,生成.o文件
gcc -S 生成汇编文件,即.s文件
gcc -o 改变生成的文件的名字
gcc -Wall 显示更多的警告信息
gcc 编译加链接
gcc /-c/-o必须会。
二、C文件扩展后缀名
.a 静态对象库
.c 需要预处理的C语言源代码
.h C语言源代码头文件
.i 不需要预处理的C语言源代码
.o 目标文件
.s 汇编语言代码 .so 共享对象库
必须得有主函数才可以链接,但是可以用gcc -c编译
三、预处理指令
C程序中允许使用指令,指令就是以#开头的。指令在预处理阶段
转换为纯C语法。
指令分类:
1 #include (用于包含一个其他的文件,主要是头文件)
#include 后面支持两种格式:<>和"",区别是<>只查找系统的
文件路径,""会先查找当前目录,然后再查找系统路径。
2 #define 和 #undef定义/取消宏变量或宏函数
3 条件编译(即按条件选择编译的分支)
#if、#elif、#else、#endif
#ifdef、#ifndef
以上3条是最常用的指令
补充几个指令:
1 #error和#warning产生一个错误或警告
举例:(这里只是举个例子,一般没有人这样写)
#include <stdio.h>
#define VERSION 3
#if(VERSION < 3)
#error "版本低"
#elif(VERSION > 3)
#warning "版本高"
#endif
int main() {
printf("hallo c\n");
return 0;
}
2 #pragma提供一些额外的功能
(1)#pragma GCC dependency 文件名
这个语句的含义是,让当前文件依赖于dependency后面的文件,
如果dependency后面的文件比当前文件新(修改的时间),就会产生警告。
(2) #pragma GCC poison 单词
定义某个单词为“毒药”,禁止使用,否则产生错误
注:在#pragma之前的代码可以使用,之后不能
(3)#pragma pack(int) - 这是比较实用的
对齐与补齐
对齐 就是每个成员必须放在自己大小的整数倍位置(大于4字节的按4字节算)
补齐 就是每个“结构”的大小应该是最大的成员的整数倍(大于4字节的按4字节算)
举例:
struct s{
char c1;
int i;
char c2;
};/*则c1是第1个字节,i是第5到8个字节,c2是第9个字节,由于补齐原则,结
*构体为12个字节*/
struct s{
char c1;
short s;
int i;
char c2;
};/*则c1是第1个字节,s是第3到第4个字节,i是第5到8个字节,c2是第9个字节,由于补齐原则,结
*构体为12个字节*/
struct s{
char c1;
short s;
char c2;
};/*则c1是第1个字节,s是第3到第4个字节,c2是第5个字节,由于补齐原则,结
*构体为6个字节*/
对齐补齐浪费了空间,但是有寻址效率高的优点 有些时候,不需要对齐和补齐或者是改变对齐和补齐的单位 可以用pragma
pack()可以改变对齐和补齐的方式 比如:pack(1)按1字节对齐和补齐,其实就是不做对齐和补齐了。
pack(2)按2字节对齐和补齐。 举例:
#include <stdio.h>
#pragma pack(2)
int main() {
struct s{
char c1;
int i;
char c2;
};
printf("size=%d\n",sizeof(struct s));
return 0;
}
运行结果:size=8;
四、头文件
头文件(.h)中定义什么?
各种声明都应该定义在头文件中,是对外的清单。各种声明包括:变量声明
宏的声明、结构和联合、函数的声明。
各种声明具体的实现都定义在源文件(.c)中,是具体的代码。具体实现包括
变量的赋值、函数的代码。
头文件的基本格式:
#ifndef XXXX_H_
#define XXXX_H_
//各种声明
#endif
怎么用头文件写程序呢?
先写一个add.c文件
/这里add和add2这两个函数1不相互引用,所以不用写#include “add.h”/
int add(int a,int b){
return a + b;
}
int add2(double a,double b){
return a + b;
}
再写头文件add.h
#ifndef ADD_H_
#define ADD_H_
int add(int,int);
double add2(double,double);
#endif
最后写由主函数的test.c文件
#include <stdio.h>
#include "add.h"
int main() {
int r1 = add(2,3);