gcc编译的背后(预处理、编译、汇编和链接) 一

来源:互联网 发布:物理其实很简单. 淘宝 编辑:程序博客网 时间:2024/04/29 22:20

本次将分为四个章节来讲,分别来讲述一下gcc编译背后的四个步骤。

第一部分:预处理。

相信大家对这一块其实挺了解了,下面我就献丑,以自己的理解再讲一遍。

预处理是c语言从源代码变成可执行程序的第一步,它包括头文件的包含,宏定义扩展,条件编译的选择等。

首先介绍一下预处理的命令:一共有12条预处理的命令,都是以#开头且每个预处理命令必须独占一行,它的结尾没有分号,因为它不是语句。

#if
#ifdef
#ifndef
#else
#elif
#endif
#define
#undef
#line
#error
#pragma
#include

 

1.#if  经常用于调试用

比如一段代码我们暂时不用,那么把这段代码用#if括起来是一个很好的选择,如

#if 0

...

#endif

 

2.#ifdef

判断那个宏是否已经定义过了,如果定义了则进行相应的处理。

#ifdef TEST_SUPPORT

int test;

#endif

3.#ifndef 则相反,很多时候用于包含头文件,避免重复包含与重复定义。

如test.h

#ifndef TESTDEC_POSTPROCESSCODEBLOCKMESSAGE_H
#define TESTDEC_POSTPROCESSCODEBLOCKMESSAGE_H

void testDec_PostProcessCodeBlockMessage(void **state);

#endif

这样的话,不管这个test.h被包含多少次,这个函数都只会被申明一次,避免了重复申明。

4.#else则于c语言中的else 类似,#elif 则与c语言的else if 类似。

5.#define 最常见了,我就不详细说明了,主要包含头文件用的。

6.#undef  取消宏定义

7.#line 改变__LINE__和__FILE__的内容

用法:#line number "filename"

大家可以自己测试一下。

8.#pragma

它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作,如

#pragma message(“消息文本”)

当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。

这条命令比较复杂,如果大家有兴趣,可以自己再去查看一下。

 

有两个预处理操作符:#和##,它们可以在#define中使用。
操作符#通常称为字符串化的操作符,它把其后的串变成用双引号包围的串。例如:
#include <stdio.h>
#define mkstr(s) #s
int main(void)
{
 Printf(mkstr(I like C));
 
 Return 0;
}
预处理程序把以下的语句:
Printf(mkstr(I like C));
变成
Printf(“I like C”);
操作符##把两个标记拼在一起,形成一个新标记。例如:
#include <stdio.h>
#define concat(a,a) a##b
int main(void)
{
 Int xy = 10;
 Printf(“%d”,concat(x,y));
 Return 0;
}
预处理程序把以下语句:
Printf(“%d”,concat(x,y));
变成
Printf(“%d”,xy);
操作符#和##主要作用是允许预处理程序对付某些特殊情况,多数程序中并不需要。

 

预定义宏
C规范了5个固有的预定义宏,它们是:
__LINE__
__FILE__
__DATE__
__TIME__
__STDC__
 
__LINE__和__FILE__包含正在编译的程序的行号和文件名。
__DATE__和内容形如month/day/year(月/日/年)的串,代表源文件翻译成目标码的日期。
__TIME__中的串代表源代码编译成目标码的时间,形如hour:minute:second(时:分:秒)
如果__STDC__的内容是十进制常数1,则表示编译程序的实现符合标准C。

 

打印出预处理之后的结果:gcc -E hello.c

在命令行定义宏:gcc -Dmacro hello.c

原创粉丝点击