导航:首页 > 源码编译 > 预编译指令和头文件声明

预编译指令和头文件声明

发布时间:2023-02-08 12:38:28

1. c语言编译预处理

编译,编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并且按照操作系统对可执行文件格式的要求链接生成可执行程序。

如果用一张图来表示:

读取c源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理

[析] 伪指令主要包括以下四个方面

(1)宏定义指令,如#define Name TokenString,#undef等。对于前一个伪指令,预编译所要做的是将程序中的所有Name用TokenString替换,但作为字符串常量的Name则不被替换。对于后者,则将取消对某个宏的定义,使以后该串的'出现不再被替换。

(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif,等等。这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉

(3)头文件包含指令,如#include "FileName"或者#include 等。在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。

包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在/usr/include目录下。在程序中#include它们要使用尖括号(<>)。另外开发人员也可以定义自己的头文件,这些文件一般与c源程序放在同一目录下,此时在#include中要用双引号("")。

(4)特殊符号,预编译程序可以识别一些特殊的符号。例如在源程序中出现的LINE标识将被解释为当前行号(十进制数),FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。

注意:

预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的,但内容有所不同。下一步,此输出文件将作为编译程序的输出而被翻译成为机器指令。

2. 预编译的编译指令

预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。常见的预编译指令有:
(1)#include 指令
该指令指示编译器将xxx.xxx文件的全部内容插入此处。若用<>括起文件则在系统的INCLUDE目录中寻找文件,若用 括起文件则在当前目录中寻找文件。一般来说,该文件是后缀名为h或cpp的头文件。
注意:<>不会在当前目录下搜索头文件,如果我们不用<>而用把头文件名扩起,其意义为在先在当前目录下搜索头文件,再在系统默认目录下搜索。
(2)#define指令
该指令有三种用法:
第一种是定义标识,标识有效范围为整个程序,形如#define XXX,常与#if配合使用;
第二种是定义常数,如#define max 100,则max代表100(这种情况下使用const定义常数更好,原因见注1);
第三种是定义函数,如#define get_max(a, b) ((a)>(b)?(a):(b)) 则以后使用get_max(x,y)就可以得到x和y中较大的数(这种方法存在一些弊病,见注2)。
第四种是定义宏函数,如#define GEN_FUN(type) type max_##type(type a,type b){return a>b?a:b;} ,使用时,用GEN_FUN(int),则此处预编译后就变成了 max_int(int a,int b){return a>b?a:b;},以后就可以使用max_int(x,y)就可以得到x和y中较大的数.比第三种,增加了类型的说明。
(3)#if、#else和#endif指令
这些指令一般这样配合使用:
#if defined(标识) //如果定义了标识
要执行的指令
#else
要执行的指令
#endif
在头文件中为了避免重复调用(比如说两个头文件互相包含对方),常采用这样的结构:
#if !(defined XXX) //XXX为一个在你的程序中唯一的标识符,
//每个头文件的标识符都不应相同。
//起标识符的常见方法是若头文件名为abc.h
//则标识为abc_h
#define XXX
真正的内容,如函数声明之类
#endif
注1:因为:const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误(边际效应)。
注2:例如get_max(a++, b)时,a++会被执行多少次取决于a和b的大小!所以建议还是用内联函数而不是这种方法提高速度。虽然有这样的弊病,但这种方法的确非常灵活,因为a和b可以是各种数据类型。
注3:可以查看网络的预处理命令,编排的比较简明。

3. 头文件 & 预编译指令

编译器在处理每个cpp之前,首先进行一个预处理:将所有的 #include 行替换成头文件的具体内容,形成一个中间文件,然后再对这个中间文件进行编译。

这个在编译之前的预处理过程 ,称为“预编译”过程。

注:如果头文件里还有 #include ,则反复替换,直到没有任何 #include 指令为止。

预处理指令不是语句,行尾不要加分号

在程序中应该尽量少用这两种 #define

取代的办法是:

(1) 定义变量或const常量

(2) 定义inline函数

把 class 的成员函数的定义写在 class 之外,即 class 的大括号的外面

这种写法:

按照一贯的原则:类型定义写在 头文件.h 里,函数实现写在 源文件.cpp 里

4. c++中头文件的声明应该在哪定义比较好

任何头文件内部都不应该放置函数体,否则包含一次就重复定义一次,是否存在重复定义只是看你是否重复包含了,和哪个平台没有关系.楼下说得那些预编译指令也没有啥帮助

5. c++ 预编译问题 关于头文件

预编译不能这么写吧?你想达到的目的是不让ElemType不重复定义?
这样试试

#ifndef HEADER_ELEM_TYPE_H
#define HEADER_ELEM_TYPE_H
struct ElemType{
int number; //物品编号
int weight;
};
#endif

int main(){
ElemType a;
}

用这个宏HEADER_ELEM_TYPE_H来判断当前文件是否被包含

如果你用vs2008的话应该可以用另外一个宏指令达到你上面的目的

#pragma once
struct ElemType{
int number; //物品编号
int weight;
};

这样多简单

6. 什么是预编译,何时需要预编译

预编译又称为预处理,是做些代码文本的替换工作

预编译又称为预处理,是做些代码文本的替换工作

处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等

就是为编译做的预备工作的阶段

主要处理#开始的预编译指令

预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。常见的预编译指令有:

(1)#include 指令

该指令指示编译器将xxx.xxx文件的全部内容插入此处。若用<>括起文件则在系统的INCLUDE目录中寻找文件,若用" "括起文件则在当前目录中寻找文件。一般来说,该文件是后缀名为"h"或"cpp"的头文件。

注意:<>不会在当前目录下搜索头文件,如果我们不用<>而用""把头文件名扩起,其意义为在先在当前目录下搜索头文件,再在系统默认目录下搜索。

(2)#define指令

该指令有三种用法:

第一种是定义标识,标识有效范围为整个程序,形如#define XXX,常与#if配合使用;

第二种是定义常数,如#define max 100,则max代表100(这种情况下使用const定义常数更好,原因见注1);

第三种是定义"函数",如#define get_max(a, b) ((a)>(b)?(a):(b)) 则以后使用get_max(x,y)就可以得到x和y中较大的数(这种方法存在一些弊病,见注2)。

第四种是定义"宏函数",如#define GEN_FUN(type) type max_##type(type a,type b){return a>b?a:b;} ,使用时,用GEN_FUN(int),则此处预编译后就变成了 max_int(int a,int b){return a>b?a:b;},以后就可以使用max_int(x,y)就可以得到x和y中较大的数.比第三种,增加了类型的说明。

(3)#if、#else和#endif指令

这些指令一般这样配合使用:

#if defined(标识) //如果定义了标识

要执行的指令

#else

要执行的指令

#endif

在头文件中为了避免重复调用(比如说两个头文件互相包含对方),常采用这样的结构:

#if !(defined XXX) //XXX为一个在你的程序中唯一的标识符,

//每个头文件的标识符都不应相同。

//起标识符的常见方法是若头文件名为"abc.h"

//则标识为"abc_h"

#define XXX

真正的内容,如函数声明之类

#endif

7. 关于C++的头文件!

头文件中通常是宏定义、结构声明、类声明,函数声明,还有你的程序中需要用到的头文件名,然后相应的实现写在源文件中。
比如:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
这些都写到头文件里,便于维护

8. C++中using namespace中预编译和声明单个名称使用冲突的问题

我也遇到这个问题,也找到了解决办法,但不觉得完美算账,但可以给你看看:
命名空间声明是与

命名空间nsdebug / /命名空间nsdebug宏定义组合在另一个文件

整数GetStringWidth(字符* s)的定义;

整数GetCellValue(诠释十,诠释y);

#定义GetStringWidth nsdebug :: GetStringWidth

#定义GetCellValue nsdebug :: GetCellValue

这些名字最近增加的空间,然后一个一个来定义一个宏做到一个新的头文件。这样的话就不必任何原代码的内容。
但后来我觉得用宏或不稳定的心脏,更多的东西比宏陷阱第二天早上相遇,后来放弃了这种方法。

9. 既然预编译只是起一个声明的作用,为什么不在工程中每个c文件中包含所有的头文件呢这样不是很方便么

预编译的时候会把包含的头文件展开,即把头文件里面的内容展开在当前文件中,如果包含所有头文件,第一会很占空间,因为有些头文件里面的变量(比如有很大的数组或者什么的)在当前这个文件并没有用到;其次很耗时间,因为要一个个去展开;第三,撇开时间和空间消耗不说,可能会存在不同头文件中声明或者定义了同名变量,这样在编译的时候就会报错。但是你却很难找到错误,因为头文件里面的东西你看不见,其次还可能引起一个重复包含的问题,比如头文件A.h包含了B.h,你在当前.c文件中如果#include"A.h" 后又#include"B.h" 的时候就会报错了,因为你重复包含了,当然重复包含可以通过#ifdef#endif机制解决。但是你不能保证每个头文件中都做了这样的操作。

阅读全文

与预编译指令和头文件声明相关的资料

热点内容
千聊免费课程可以重新加密吗 浏览:507
python能代替php吗 浏览:252
phpexcel样式 浏览:265
安卓手机有没有什么软件可以阻止弹广告的 浏览:306
linux局域网搭建服务器 浏览:690
python编译器mac 浏览:293
windows的doc命令 浏览:463
nfc全加密门禁卡 浏览:636
身份信息被加密 浏览:482
我的盐城app怎么添加不了家庭成员 浏览:493
php商城并发 浏览:348
熊猫绘画app怎么做出大佬的笔刷 浏览:603
云存储服务器知识 浏览:461
服务器cpu是什么指令集 浏览:591
糖猫t10怎么安装app 浏览:992
电脑加密u盘怎么使用 浏览:518
linux如何升级php版本升级 浏览:841
二级程序员c语言难度 浏览:353
批处理编译qt 浏览:67
铁友app怎么查询机票订单 浏览:197