第二章 预处理

一、文件的包含方式

1)#include"文件名"
2)#include<文件名>

  查找文件的顺序不同,一个先从当前目录开始查找;一个先从系统目录开始查找。

二、宏定义

  0.基础介绍

  宏定义又称为宏替换,是在预处理阶段用预先定义的字符串替代标示符的过程。其定义一般形式为:

#define  标示符  字符串

  宏定义的标示符一般情况下都大写,这是一种约定俗成的习惯。使用宏定义需要注意以下几点:

  1)宏替换不做语法检查,使用的时候要特别小心

  2)宏替换通常在文件开头部分,写在函数的花括号外边,作用域为气候的程序,直到#undef命令终止宏定义的作用域

  3)不要在字符串中使用宏,如果宏名出现在字符串中,那么将按字符串进行处理

  1.简单宏替换

  宏定义的优点:1)减少不必要的修改,提升程序的可阅读性 2)提升代码的可移植性

  使用宏定义需要注意的问题:宏定义只是简单的替换,要清楚的理解其替换后的意义

  2.带参数的宏替换

  带参数的宏替换,其定义的一般形式为:

#define 宏名(参数表) 字符串

  使用带参数的宏时需要注意以下几点:

  1)宏名和参数表的括号间不能有空格

  2)宏替换只做替换,不做计算和表达式求解

  3)函数调用在编译后程序运行时进行,并且分配内存,宏替换在编译前进行,不分配内存

  4)宏的哑实结合(哑实结合类似于函数调用过程中实参替代形参的过程)不存在类型,也没有类型转换

  两个标准的宏,但是只能在linux下运行:

#define min(x,y) ({typeof(x)_x = x;typeof(y)_y=y;(void)(&_x==&_y);_x<_y?_x:_y;})
#define max(x,y) ({typeof(x)_x = x;typeof(y)_y=y;(void)(&_x==&_y);_x>_y?_x:_y;})

  可以细细去体会其中的奥妙:a.typeof的意义是什么?b.void(&_x==&_y)的意义是什么?c.为什么要加{}?4.为什么外面需要()?

  3.宏定义实现变参

  带变参的宏的一般形式为:

#define print(......) printf(__VA_ARGS__)

  在这个宏中,“......”指可变参数。可变参数的实现方式就是使用“......”所代表的内容替代__VA_ARGS__,下面代码演示:

#include<stdio.h>
#define print(......) printf(__VA_ARGS__)
int main(int argc, char *argv)
{
        print("hello world----%d
",1111);
        return 0;
}

三、条件编译指令的使用

  预处理程序提供了条件编译的功能,用户可以选择性地编译程序,进而产生不同的目标代码文件,这对程序的移植性和调试来说是非常有用的。下面来看条件编译命令的几种使用方式:

1)第一种方式:

#if 常量表达式
程序段1;
#else
程序段2;
#endif

2)第二种方式:

#ifdef 标示符
程序段1;
#else
程序段2;
#endif

3)第三种方式:

#ifndef 标示符
程序段1;
#else
程序段2;
#endif

 四、#pragma指定的使用

  预处理#pragma指令的作用不只是指定字节对齐,其作用是设置编译器的状态或指示编译器完成一些特定的动作。

  1.#pragma mesage("消息")

  该打印输出的信息是在编译期输出,不会出现在程序最终的运行结果中。通过这种方式,可以在代码中输出想要的信息,也可以看某个宏是否已经被定义过。

#include<stdio.h>
#define STR
void main(int argc, _TCHAR* argv[])
{
	printf("学习#pragma命令中message参数的使用!
");
#ifdef STR
#pragma message("STR已经定义过了。")
#endif
	return;
}

  2.#pragma once

  如果在头文件的开头部分加入这条指令,那么就能保证头文件只被编译一次

  3.#pragma hdrstop

  该指令表示编译头文件到此为止,后面的无需再编译了

  4.#pragma pack()

  设定字节对齐

  5.#pragma warning()

原文地址:https://www.cnblogs.com/cauchy007/p/4547986.html