一、C语言的执行流程
(一)编译
编译器将源代码转换成机器语言的过程。在编译过程中,会找出并报告错误,最后形成源文件(在Windows下是扩展名为.obj的文件,在Linux或者UNIX环境中是.o)。
编译过程包括两个阶段。第一个阶段称为预处理阶段,在此期间会修改或添加代码,第二个阶段是生成对象代码的实际编译过程。
(二)链接
将源文件(.obj或者.o文件)和C函数库连接合并,形成最终的可执行文件(Windows下扩展名为.exe,UNIX环境下没有扩展名,但它是一个可执行的文件类型)。
(三)执行
在这个阶段,计算机最终会精确地执行指令。
图1-1 创建和执行程序
二、预编译(预处理):为编译工作做准备工作,完成代码文本的替换工作
(一)预处理指令
符号#表示这是一个预处理指令(preprocessing directive),告诉编译器在编译源代码之前,要先执行一些操作。
1.include指令
#include <stdio.h>
,这是将stdio.h文件的内容包含进来,stdio文件称为头文件
。
2.define指令(也叫宏定义、宏替换或者预编译指令)
1.定义标示
-
#ifdef __cplusplus
:标识支持C++语法 -
#pragma once
:防止文件重复引入:
图2-1 文件重复引用
如图所示.c
源文件引用了A.h
的头文件,A.h
又和B.h
存在相互引用的关系,那么A和B两个头文件就会造成重复引入的错误。
图2-2 文件重复引用错误
解决办法是,在A.h
和B.h
头文件的开头使用#pragma once
,它表示该头文件只被包含一次,编译器会自动处理好循环包含的问题。
//A.h
#pragma once
#include "B.h"
void printfA();
//B.h
#pragma once
#include "A.h"
void printfB();
2.定义常数(便于修改与阅读)
#define MAX 200
3.定义“宏函数”
- 示例代码如下
#include <stdio.h>
#include <stdlib.h>
void com_gjg_jni_read(){
printf("read\n");
}
void com_gjg_jni_write(){
printf("write\n");
}
//##表示要替换的部分
#define jni(name) com_gjg_jni_##name();
void main(){
//根据传入的name值,决定调用哪个函数
jni(read);
jni(write);
getchar();
}
图2-3 宏函数
- 示例代码如下
#include <stdio.h>
#include <stdlib.h>
//__VA_ARGS__表示可变参数
#define LOG(FORMAT,...) printf(##FORMAT,__VA_ARGS__);
#define LOG_I(FORMAT,...) printf("INFO:"); LOG(##FORMAT,__VA_ARGS__);
#define LOG_E(FORMAT,...) printf("ERROR:"); LOG(##FORMAT,__VA_ARGS__);
void main(){
LOG_I("%s,%d\n", "我是详细信息",12);
LOG_E("%s,%d\n", "我是错误信息",24);
getchar();
}
图2-4 宏函数
(二)定义自己的头文件
可以定义自己的头文件,通常扩展名是.h
,头文件名称通常用小写,可以使用操作系统允许的任何文件名。头文件不能包含实现代码,即可执行代码。可以在头文件中放置函数原型、struct类型定义、符号定义、extern语句和typedefs。一个常用的技巧是创建一个头文件,它含有程序中所有函数的原型以及类型声明。
END