C++ 預編譯命令
C++預處理指令包括:
#include
#define
#undef
#pragma
#import
#error
#line
#ifdef
#ifndef
#if
#else
#elif
#endif
宏以#起始 不以;結束
一. #include 文件包含
預編譯期發現#include后,將會尋找HeaderName并把其包含到當前文件中
EG:#include <HeaderName>
常見形式:
#include <iostream.h> //
#include <iostream> //
#include "iostream" //
#include "TestHeader.h" //
#include "../TestHeader.h" //
1. #include <iostream.h>和#include <iostream>區別
#include <iostream.h>是老規范,現已經拋棄
#include <iostream>是新規范,使用名稱空間避免名稱沖突。即將所有的定義放在了一個名稱空間std中
2. #include <iostream>和#include "iostream"區別
#include <iostream>直接在系統的路徑下查找此頭文件。多是系統的頭文件
#include "iostream"首先在當前目錄查找,如果沒有找到再到系統目錄查找
3. 頭文件的多次包含問題
編譯器對每個文件只編譯一次生成一份機器代碼.obj,如果在多個地方包含了同一個頭文件,則會出現多次包含的錯誤,即試圖讓編譯器將此文件編譯多次生成多份機器代碼。
預編譯保護解決此問題。
二. #define #undef 宏替換
#define 宏 宏主體
宏展開:在代碼中出現宏,會用宏實體代替宏
#define 定義常量、函數宏
#undef 結束常量、函數宏定義
1. 常量宏
常量宏:是最常見的一種形式。即使用一個宏代替實際的常量,如數據、字符、字符串常量等
#define CONST_VAL 2
#define MEG_EG "Test Macro!"
#define CHARACTOR_EG 'M'
注:
(1) 可以使用#undef結束常量宏定義,結束宏定義宏此宏不能再次使用。即時這個宏實際不存在,使用#undef結束宏定義也不是錯誤,相反在定義一個宏時如果不確定其是否已經定義可以先使用#undef結束其定義,然后重新定義
(2) 可以多次定義同一個宏
2. 函數宏
函數宏:外形和作用都與函數類似并且有參數輸入
#define MAX(x, y) ( (x>y)?x:y )
注:
(1) 定義函數宏是將宏體都用一個“( ) “括起來。
#define MAX(x, y) ( (x>y)?x:y )
cout << "MAX = " << MAX(1,2) << endl; //正確
#define MAX(x, y) (x>y)?x:y
cout << "MAX = " << MAX(1,2) << endl; //錯誤。將<<和宏混淆
(2) 通常將函數宏第一為一行,但可以使用“/“定義多行宏函數
#define MAX(x, y) ( (x>y)?/
x:y )
(3) 可以使用#undef結束函數宏定義
#undef MAX(x, y)和#undef MAX都可以
(4) 宏函數產生內聯代碼,形式上等同與inline函數,當沒有inline函數安全
(5) 宏函數不檢查輸入的參數(相比inline函數不安全)
(6) 宏函數沒有inline函數效率高
3. #運算符
#運算符可以在一個字符串中輸入宏參數,使得一個字符串可以包含某個參數
EG:
#define STR_A(A) ( printf("STR_A(A) A = "#A" ") )
#define STR_B(B) ( "STR_B(B) B = "#B" " )
#define STR_C(CA, CB) ( "STR_C(CA, CB) C = "#CA" "#CB" " )
STR_A(1);
cout << endl;
cout << STR_B(2) << endl;
cout << STR_B(B) << endl;
cout << STR_C(CA, CB) << endl;
string strB = "strB ";
strB += " + ";
strB += STR_B(B);
cout << "strB + Macro STR_B = " << strB << endl;
4. ##運算符
##運算符用于創建變化的變量,即使用宏參數創建變化的變量
EG:
#define VARIAVLE_NAME(N) ( n##N )
int VARIAVLE_NAME(IntA) = 1; // int nIntA
int VARIAVLE_NAME(1) = 1; // int n1
int VARIAVLE_NAME(2) = 1; // int n2
cout << "nIntA = " << nIntA << endl;
cout << "n" << 1 <<" = " << VARIAVLE_NAME(1) << endl;
cout << "n" << 2 <<" = " << VARIAVLE_NAME(2) << endl;
double VARIAVLE_NAME(DoubleA) = 1.1;
cout << "nDoubleA = " << nDoubleA << endl;
三. #pragma
其格式一般為: #pragma para
其中para 為參數,下面來看一些常用的參數。
(1) #pragma once
多次包含的保護。只要在頭文件的最開始加入這條指令就能夠保證頭文件被編譯一次,這條指令實際上在VC6中就已經有了,但是考慮到兼容性并沒有太多的使用它。
等價于:(此為C/C++標準 通用性更強)
#ifndef HEADER_NAME_HPP
#define HEADER_NAME_HPP
Your Code
#endif //END HEADER_NAME_HPP
(2) #pragma warning()
#pragma warning( warning-specifier : warning-number-list
[; warning-specifier : warning-number-list...] )
#pragma warning( push[ ,n ] )
#pragma warning( pop )
EG:
#pragma warning( disable : 4507 34; once : 4385; error : 164 )
等價于:
#pragma warning(disable:4507 34) // 不顯示和號警告信息
#pragma warning(once:4385) // 4385號警告信息僅報告一次
#pragma warning(error:164) // 把號警告信息作為一個錯誤。
同時這個pragma warning 也支持如下格式:
#pragma warning( push [ ,n ] )
#pragma warning( pop )
這里n代表一個警告等級(1---4)。
#pragma warning( push )保存所有警告信息的現有的警告狀態。
#pragma warning( push, n)保存所有警告信息的現有的警告狀態,并且把全局警告
等級設定為n。
#pragma warning( pop )向棧中彈出最后一個警告信息,在入棧和出棧之間所作的
一切改動取消。例如:
#pragma warning( push )
#pragma warning( disable : 4705 )
#pragma warning( disable : 4706 )
#pragma warning( disable : 4707 )
//.......
#pragma warning( pop )
在這段代碼的最后,重新保存所有的警告信息(包括,和)。
(3) #pragma warning()
#pragma warning( warning-specifier : warning-number-list
[; warning-specifier : warning-number-list...] )
#pragma warning( push[ ,n ] )
#pragma warning( pop )
EG:
#pragma warning( disable : 4507 34; once : 4385; error : 164 )
等價于:
#pragma warning(disable:4507 34) // 不顯示和號警告信息
#pragma warning(once:4385) // 4385號警告信息僅報告一次
#pragma warning(error:164) // 把號警告信息作為一個錯誤。
同時這個pragma warning 也支持如下格式:
#pragma warning( push [ ,n ] )
#pragma warning( pop )
這里n代表一個警告等級(1---4)。
#pragma warning( push )保存所有警告信息的現有的警告狀態。
#pragma warning( push, n)保存所有警告信息的現有的警告狀態,并且把全局警告
等級設定為n。
#pragma warning( pop )向棧中彈出最后一個警告信息,在入棧和出棧之間所作的
一切改動取消。例如:
#pragma warning( push )
#pragma warning( disable : 4705 )
#pragma warning( disable : 4706 )
#pragma warning( disable : 4707 )
//.......
#pragma warning( pop )
在這段代碼的最后,重新保存所有的警告信息(包括,和)。
四. #import
常用于導入.dll
五. #error
該指令用于程序的調試, 當編譯中遇到#error指令就停止編譯。
#if !defined(__cplusplus)
#error C++ compiler required.
#endif
如果沒有在__cplusplus環境下,就會輸出This software requires the cplusplus OS.然后誘發編譯器終止。所以總的來說,這條指令的目的就是在程序崩潰之前能夠給出一定的信息。
六. #line
用于重置__FILE__和__LINE__
初看起來似乎沒有什么用,不過,他還是有點用的,那就是用在編譯器的編寫中,我們知道編譯器對C++源碼編譯過程中會產生一些中間文件,通過這條指令,可以保證文件名是固定的,不會被這些中間文件代替,有利于進行分析
重置后
七. #ifdef #ifndef #if #else #elif #endif 條件編譯
預處理器不能識別標記代碼塊的花括號{},對于條件編譯的沒有條件判斷塊必須使用 #endif來指定終止
1、
#ifdef identifier
your code
#endif
如果identifier為一個定義了的符號,your code就會被編譯,否則剔除
2、
#ifndef identifier
your code
#endif
如果identifier為一個未定義的符號,your code就會被編譯,否則剔除
3、
#if expression
your code
#endif
如果expression非零,your code就會被編譯,否則剔除
4、
#ifdef identifier
your code1
#else
your code2
#endif
如果identifier為一個定義了的符號,your code1就會被編譯,否則your code2
就會被編譯
5、
#if expressin1
your code1
#elif expression2
your code2
#else
your code3
#enif
八. 預定義宏
__DATE__ 進行預處理的日期
__FILE__ 當前軟代碼文件名的字符串文字
__LINE__ 當前源代碼中的行號的整數常量
__TIME__ 源文件的編譯時間
__TIMESTAMP__ 源文件的編譯完整時間
cout << "__DATE__ = " << __DATE__ << endl;
cout << "__FILE__ = " << __FILE__ << endl;
cout << "__LINE__ = " << __LINE__ << endl;
cout << "__TIME__ = " << __TIME__ << endl;
cout << "__TIMESTAMP__ = " << __TIMESTAMP__ << endl;