#c语言#
预编译语句是C/C++语言的一大特色,大部分的C/C++程序文件中都有预编译语句,比如说#include
#include
该语句后面一般跟头文件,用方括号括起来的头文件表示编译器指定的include目录里的文件,而用引号表示的头文件可以是任何目录下的。比如我手动建了一个头文件,名叫pch.h,如果这个文件是和使用这个语句的文件同目录的,那么#include "pch.h"就可以包含这个头文件。如果这个文件在其他路径上,那么#include "路径pch.h"就可以包含这个头文件。在linux系统中,符号""要改为"/",原因是windows系统和linux系统的路径表示方式不同。一般为了兼容不同计算机,我们使用相对路径的办法来包含头文件。比如头文件的路径为".afxpch.h",而源文件的目录为".",则我们可以使用#include "afxpch.h"来包含这个头文件。
该语句的作用可以理解为用包含的头文件的内容直接替换掉那行#include语句,聪明的读者看到这里一定想到了,如果我包含了多个重复的头文件怎么办,不会出现重复定义之类的错误吗?下面谈到这些语句就和这个问题有关。
#define 和 #undef
这两个语句是定义宏和取消定义宏的语句,宏是一个标识符,为了和变量区分,通常全部用大写字母表示,可以用于程序里的常量替换,语句替换,而且能够通过判断是否定义了该标识符进行选择编译等。
宏的第一个作用是作为程序里的常量,比如#define MAX_SIZE 100这个语句,该语句会把它作用范围内的所有 MAX_SIZE 替换成100,这个被替换的常量,既可以是字面上的常量,比如100, "a", 3.14f等,也可以是一段语句,比如#define PAUSE system("pause"); 这个就可以作为暂停程序的语句使用。宏的第二个作用是实现特殊的函数功能,宏在定义的时候可以带参数,而宏仅仅是常量替换,无关乎数据类型,因此可以在C语言上实现类似C++函数模板的功能。
比如#define SWAP(x, y) (x = x + y, y = x - y, x = x - y) 如果不考虑溢出的问题,那么只要这两个变量能够加减和赋值,那么这个语句对于任何类型的变量都能进行交换值,虽然不一定是想要的结果。
#ifdef 和 #ifndef 等
这些语句主要用于条件编译,#ifdef 意思为假如定义了某个宏,是的话则运行#ifdef下面的预编译语句,编译其中的程序代码,否则跳转至#else,如果没有#else,则直接跳转到#endif。而#ifndef 的功能则恰好相反,没有定义某个宏才执行,否则跳转至#else 或#endif。#if 作用的对象为常量表达式,而#elif 相当于#else 和 #if 缩写成了一个语句,下面举一个例子来说明#if 的作用。
如果对计算机的内存知识有一定了解的话,那么可能就知道,函数声明的数组占用的是内存栈上面的空间,而这个空间是有限的。假如这个空间大小为1024字节,那么如果我声明的数组大小大于这个值,就会爆栈出错,即经典的Stack Overflow错误。为了避免这个错误,我们便会选择在空间更大的内存堆里面分配空间给数组。
另外C++有一个宏__cpluscplus,这个宏的值就代表C++标准的版本,我们可以通过这一点来利用#if 实现兼容不同C++标准的代码。不过相比#if,我们用得最多的还是#ifndef,这可以用来避免头文件的内容重复编译。
我们先#ifndef 标识符,这个标识符是头文件的唯一标识符,通常命名为头文件的全大写名字加下划线,比如说stdio.h的标识符为_STDIO_H,假如没有定义这个标识符,我们就先定义,如#define _STDIO_H 然后编译下面的代码,直到遇到#endif。如果定义了这个标识符,编译器就会直接跳转至#endif 后,从而防止了重复编译。在VC中,有更简单防止重复编译的方法,#pragma once,这行语句能直接实现整个头文件只编译一次,并且效率高于#ifndef 实现的,不过#pragma 开头的预编译语句具体功能与具体的编译器有关,还有#error,#line 对于应用程序员并不常用等语句,有兴趣的可以自行查阅