- gcc编译器有什么用?
将代码文本编译为机器能识别的二进制指令。
- 从代码最终得到程序,经过了哪4个步骤?
预处理、编译、汇编、链接
- 经过哪个步骤之后,代码不能直接阅读了?
汇编。
- 对于代码的语法检查(提示错误行号)属于在哪个步骤进行?
编译。
- 为什么代码漏写函数,gcc编译时不提示出现错误的行号?
因为函数链接定位在链接的阶段,而不是在编译阶段。
==================1.gcc编译流程==========================
- 预处理:(代码文本 ---> 预处理文本)
指令:gcc hello.c -o hello.i -E
作用:处理所有的预处理指令(以#开头,比如头文件包含、宏定义、条件编译)
- 编译:(预处理文本 ---> 汇编文件)
指令:gcc hello.i -o hello.s -S
作用:词法、语法分析,根据平台生成最接近机器的语言(汇编)。
- 汇编:(汇编文件 ---> ELF可重定位文件)
指令:gcc hello.s -o hello.o –c
作用:将汇编指令文件翻译为可直接运行的二进制指令流。
- 链接:(ELF可重定位文件 库链接 ---> 最终程序)
指令:gcc hello.o -o hello –lc -lgcc
作用:重定位(函数和全局变量等)、链接库、合并段
备注:
- 汇编阶段,是处理汇编文件,生成二进制机器指令。
- -lXXX表示链接XXX库(-l: library)
- 预处理阶段,不会对代码进行语法词法分析。
- 链接阶段会对所有函数、全局变量进行重定位、链接,如果此时出现问题,不会提示出错行号。
================== 2.预处理指令 ==========================
在源码中,以#开头的语句,称为预处理指令,他们不属于C语言语法。
- 宏定义
#define PI 3.1415926 // 预处理阶段中,将代码中所有宏进行替换。
- 条件编译(有点类似于分支结构)
#if #ifdef #ifndef #elif #else #endif
- 头文件包含
#include <stdio.h>
备注:
- 宏名一般使用全大写字母,用以区别普通变量、函数。
- 带参宏,也称为宏函数,但是不存在函数调用机制。
- 宏定义的作用:
- 可使代码更具可读性:字符单词一般比纯数字更容易理解含义。
- 使得代码更方便修改:只需修改宏定义,即修改了所有该宏定义表达式。
- 提高程序运行效率:函数的调用是需要切换时间的,而宏定义是直接展开,不占用运行时间。
- gcc编译指令中,可添加 -D选项,往工程中添加指定的宏。
可添加一些调试语句,通过编译指令去控制调试语句的输出。
gcc demo4_条件编译ifdef-ifndef.c -o demo –DTEST
- 条件编译属于预处理指令,在预处理阶段就已经完成了判断,程序运行过程中不会再次判断。
- 下列语句可避免头文件中的内容重复加入编译:
demo1_编译过程
代码语言:javascript复制#include <stdio.h>
#include <string.h>
void hahaha(char *str);
int main()
{
printf("hello world.n");
hahaha("hello world.n");
return 0;
}
demo2_define宏定义
代码语言:javascript复制#include <stdio.h>
#include <string.h>
// 不带参宏
// #define PI
#define PI 3.1415926 // 预处理阶段中,将代码中所有宏进行替换。
// 带参宏(宏函数)
#define SUM(a,b) (a b)
// 子函数
float func_sum(float a, float b);
int main()
{
printf("hello world.n");
float r = 5.0;
printf("面积: %fn", PI*r*r);
printf("周长: %fn", 2*PI*r);
float var1 = 1.2;
float sum = func_sum(r, var1)*2;
printf("sum: %fn", sum);
sum = SUM(r, var1)*2;
printf("sum: %fn", sum);
return 0;
}
float func_sum(float a, float b)
{
return a b;
}
demo3_条件编译_if-else
代码语言:javascript复制#include <stdio.h>
#include <string.h>
int main()
{
#if 0
printf("hello world.n");
printf("hello world.n");
printf("hello world.n");
printf("hello world.n");
printf("hello world.n");
printf("hello world.n");
#else
printf("nihao 123.n");
printf("nihao 123.n");
printf("nihao 123.n");
printf("nihao 123.n");
printf("nihao 123.n");
printf("nihao 123.n");
#endif
return 0;
}
demo4_条件编译ifdef-ifndef
代码语言:javascript复制#include <stdio.h>
#include <string.h>
int main()
{
#ifdef TEST
printf("[%d]n", __LINE__);
#endif
printf("nihao 123.n");
printf("nihao 123.n");
printf("nihao 123.n");
printf("nihao 123.n");
printf("nihao 123.n");
printf("nihao 123.n");
#ifdef TEST
printf("[%d]n", __LINE__);
#endif
return 0;
}
demo5_使用自己的头文件
代码语言:javascript复制#include <stdio.h>
#include <string.h>
// 包含系统头文件
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
#include "myhead.h"
// 包含自定义头文件
int main()
{
printf("%dn", ABC);
return 0;
}
myhead.h
代码语言:javascript复制#ifndef _MYHEAD_H
#define _MYHEAD_H
#define ABC 1234
#endif