c++一个文件包含处理语句_《C语言要点》第八章 编译前的处理——预处理

C语言读书摘录笔记,笔记内容绝大部分摘录整理自李春葆、李筏驰老师编著的《直击招聘——程序员面试笔试C语言深度解析》一书,少部分来自于网络博客及网上资源(尽量保留了资源原始链接)

8.1 宏定义

在C 源程序被编译之前,首先对源程序中的预处理命令进行处理,然后才对程序进行编译。编译预处理命令都是以“#“开头的,它不是C 语句,必须单独占一行,末尾不使用分号作为结束符。类似Word中的替换功能。常用的预处理命令包括宏定义、条件编译和文件包含等。

8.1.1 无参宏定义

  • 格式#define 标识符 字符串
  • 定义要点
  1. 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,属于一种简单的代换。该字符串可含任意字符,预处理时对它不作任何检查。如有错误,只能在编译已被宏替换的源程序的过程中发现问题。
  2. 当宏定义在一行中写不下, 需要在下一行继续时,只需在最后一个字符后紧接着加一个反斜线”" 。
  • 扩展阅读:反斜线可能引发的bug
  • 宏定义不是语句,在行末不必加分号,如加上分号则连分号一起被置换
  • 宏名在源程序中若用引号括起来, 则预处理程序不对其作宏替换,例如printf函数的参数中,双引号内的宏名不会被替换
  • 宏定义允许嵌套, 即在宏定义的字符串中可使用已经定义的宏名,并且在宏替换时由预处理程序层层代换

8.1.2 带参宏定义

  • 格式#define 标识符(形参表) 字符串
  • 调用宏名(实参表)
  • 定义要点
  1. 在带参宏的定义中宏名和形参表之间不能有空格出现,否则宏名后面的括号、形参表和字符串会被错误认为是无参宏
  2. 在宏定义中形参是标识符,而宏调用中的实参可以是表达式
  3. 在宏定义中字符串内的形参通常要用括号括起来,否则可能出错,这称为宏的副作用。例如,定义求正方形面积的宏如下:
    #define area(a) (a*a)
    当调用area(2+3)时宏替换成(2+3*2+3) ,那么求出的面积是11, 而不是正确的25 。所以应该改为如下:
    #define area(a) ((a)*(a))
  4. 宏定义可用来定义多个语句,在宏调用时把这些语句又代换到源程序内,例如:
    #define SET(a,b,c,d) a=1;b=2;c=3;d=4;
  • 带参宏与函数的区别
  1. 函数调用时先求出实参表达式的值,然后代入函数定义中的形参;而使用带参宏只是进行简单的字符串替换,不进行实参的计算
  2. 函数调用是在程序执行时处理的,分配临时的内存单元;而宏替换是在编译之前进行的,在宏替换时并不分配内存单元,也不进行值的传递处理,也没有“返回值"的概念
  3. 对函数中的实参和形参都要定义类型,且两者的类型要求一致,如不一致应进行类型转换;而宏不存在类型问题,宏名无类型,它的参数也无类型,只是一个符号代表,宏替换时代入指定的字符即可
  4. 当使用宏次数较多时,宏替换后使源程序变长,而函数调用不使源程序变长,因此一般用宏来替换小的、可重复的代码段,对于代码行较多的应使用函数方式
  5. 宏替换不占执行时间,只占编译预处理时间,而函数调用占执行时间(分配内存、保留现场、值传递、返回等)。

8.2 条件编译

一般情况下,C 源程序中所有的行都参加编译过程。但有时出于对程序代码优化的考虑,希望对其中一部分内容只是在满足一定条件时才进行编译,形成目标代码。这种对程序的一部分内容指定编译的条件称为条件编译。

  • 条件编译注意要点

头文件中的ifndef/define/endif 有什么作用?例如:

#ifndef _STDIO_H
#define _STDIO_H

“宏名“在理论上来说可以是自由命名的,但每个头文件的宏名都应该是唯一的,其命名规则一般是头文件名全大写,前、后加下划线, 并把文件名中的“.”也变成下划线,例如stdio. h 头文件的宏名是_STDIO_H。上述条件编译命令表示若没有定义_STDIO_H,就定义_STDIO_H 。

其目的是为了防止同一头文件等被重复引用。牛客网题目参考连接

8.3 文件包含

所谓文件包含预处理,是指在一个文件中将另一个文件的全部内容包含进来的处理过程,即将另外的文件包含到本文件中。C 提供了#include 编译预处理命令实现文件包含操作。

8.3.1 文件包含操作的两种格式

  1. #include <包含文件名>
  2. #include “包含文件名”

两者区别

第一种:<包含文件名>表示直接到指定的C/C++编译系统标准包含文件目录去寻找文件

第二种:“包含文件名”表示先在当前目录寻找,如找不到再到标准包含文件目录寻找

因此

一般来说,前者用来包含开发环境提供的库头文件,后者用来包含自己编写的头文件。

8.3.2 文件包含操作的过程

文件包含预处理的功能是在对源程序进行编译之前用包括文件的内容取代该文件包含预处理语句。例如, a.c 文件中有文件包含命令#include "b.c", 其预处理过程如下图:

c++一个文件包含处理语句_《C语言要点》第八章 编译前的处理——预处理_第1张图片

注:被包含的文件并不限于C系统所提供的头文件(如stdio.h 、string.h 等),还可以是用户自己编写的命名文件(其中包括宏、结构体名、联合体名、全局变量的定义等)和其他的要求在本文件中引用的源程序文件。

8.3.3 文件包含的说明

  1. 一个#include 命令只能指定一个包含文件。如果要包含多个文件,则要使用多个#include 命令
  2. 如果文件file1.c 要使用文件file2.c 中的内容,而文件file2.c 要用到文件file3.c 中的内容,则可以在文件file1.c 中用两个#include 命令分别包含file2.c 和file3.c, 而且文件file3.c 应出现在文件file2.c 之前,即file1.c中有:
    #include "file3.c"
    #include "file2.c"
    这样file1.c 和file2.c 均可以用file3.c 中的内容,而在file2.c 中不必再用#include "file3.c” 了
  3. 在一个被包含文件中又可以包含另一个被包含文件,即文件包含是可以嵌套的
  4. 被包含文件(如file2.c) 与其所在的文件(file1.c) 在预编译后已成为同一个文件(而不是两个文件),因此,如果file2.c 中有全局静态变量,它也在filel.c 文件中有效,不必再用extern 声明。

5. 全局变量是否可以定义在可被多个 .c 文件包含的头文件中?为什么?
如果包含该头文件(其中定义有全局变量n) 的多个.c 文件属于同一个工程,并且希望通过该全局变量n 在这些.c 文件的函数中共享数据,这是不可以的。例如,一个工程包含三个文件:
headfile.h 头文件:
int n; //全局变量
file1.c 文件:
#include
#include "headfile.h"
……
file2.c 文件:
#include
#include "headfile.h"
……
在包含文件预处理之后,相当于一个程序中两次定义全局变量n,在编译时会出现变量重复定义的编译错误。


如果将headfile.h 头文件中全局变量n的定义改为static int n;,程序正确执行,即可以在不同c文件中定义同名的全局变量,但变量n为静态全局变量,不能在多个.c文件的函数中共享数据。即,虽然此时每个文件中都有静态全局变量n,但每个文件中的变量n的地址都是不相同的,只是变量名看似相同,并非真正的全局变量。
头文件中的的static变量意味着什么?
菜鸟教程:C/C++ 中 static 的用法全局变量与局部变量

  • Silencht:《C语言要点》第一章 程序设计基础——变量
  • Silencht:《C语言要点》第二章 数据处理——控制结构
  • Silencht:《C语言要点》第三章 内存操作——指针
  • Silencht:《C语言要点》第四章 数据组织——数组
  • Silencht:《C语言要点》第五章 数据结构II——结构体与联合体
  • Silencht:《C语言要点》第六章 模块化——函数
  • Silencht:《C语言要点》第七章 位操作——位运算和位域

你可能感兴趣的:(c++一个文件包含处理语句,c语言word类型,c语言全局变量,c语言全局变量怎么定义,c语言变长数组)