1. 程式人生 > >c/c++預處理過程詳解(二)之條件編譯及預定義的巨集

c/c++預處理過程詳解(二)之條件編譯及預定義的巨集

未經博主同意不得私自轉載!不準各種形式的貼上複製本文及盜圖!


首先對於上篇文章中巨集定義的補充:

(1)#define NAME"zhangyuncong"

程式中有"NAME"則,它會不會被替換呢?

(2)#define 0x abcd

可以嗎?也就是說,可不可以用不是識別符號的字母替換成別的東西?

(3)#define NAME "zhang

這個可以嗎?

(4)#define NAME"zhangyuncong"

程式中有上面的巨集定義,並且,程式裡有句:

NAMELIST這樣,會不會被替換成"zhangyuncong"LIST

四個題答案都是十分明確的。

第一個,""內的東西不會被巨集替換。這一點應該大都知道。

第二個,巨集定義前面的那個必須是合法的使用者識別符號

第三個,巨集定義也不是說後面東西隨便寫,不能把字串的兩個""拆開。

第四個:只替換識別符號,不替換別的東西。NAMELIST整體是個識別符號,而沒有NAME識別符號,所以不替換。

也就是說,這種情況下記住:#define第一位置第二位置

(1) 不替換程式中字串裡的東西。

(2) 第一位置只能是合法的識別符號(可以是關鍵字)

(3) 第二位置如果有字串,必須把""配對。

(4) 只替換與第一位置完全相同的識別符號

Ps:上面這段來源自網路,主要是加強一下理解和實際應用中的問題。


條件編譯:

使用#if  #else #elif  #endlf

#if的一般含義是如果#if後面的常量表達式為true,則編譯它與#endif之間的程式碼,否則跳過這些程式碼。命令#endif標識一個#if塊的結束。

注意:跟在#if後面的表示式在編譯時求值,因此它必須僅含常量及已定義過的識別符號,不可使用變數。表示式不許含有操作符sizeof(sizeof也是編譯時求值)。

#else命令的功能有點象C語言中的else;#else建立另一選擇(在#if失敗的情況下)。

注意:#else屬於#if塊。

#elif命令意義與ELSE IF 相同,它形成一個if else-if階梯狀語句,可進行多種編譯選擇。#elif 後跟一個常量表達式。如果表示式為true,則編譯其後的程式碼塊,不對其它#elif表示式進行測試。否則,順序測試下一塊。

 #endif     結束一個#if……#else條件編譯塊

使用#ifdef和#ifndef

#ifdef表示“如果有定義”。有定義是指在編譯此段程式碼時是否有某個巨集通過 #define 指令定義的巨集。如果在此之前已定義了這樣的巨集名,則編譯語句段。

#ifndef表示“如果無定義”,指找不到通過#define定義的某巨集,該巨集可以是在當前檔案此條指令的前面定義的,也可以是在其它檔案中,但在此指令之前包含到該檔案中的。如果沒找到則不編譯此語句段。

#ifdef的一般使用形式:

#ifdef 巨集名
 
//語句段
#endif


#ifndef同此

 C語言的#ifdef #if defined 的區別 

#ifdef 和 #if defined 的區別在於,後者可以組成複雜的預編譯條件,比如

#if defined (AAA)&& defined (BBB)
xxxxxxxxx
#endif
 
#if defined (AAA) ||VERSION > 12
xxxxxxxxx
#endif


而#ifdef 就不能用上面的用法,也就是說,當你要判斷單個巨集是否定義時

#ifdef 和 #if defined 效果是一樣的,但是當你要判斷複雜的條件時,只能用 #if defined

使用#defined和#undef

#define 定義一個巨集定義。

使用形式:

#define MAX 100


#undef 取消其後那個前面已定義過有巨集名定義。

使用形式:

#undef macroname


其他指令:

#error強迫編譯程式停止編譯,主要用於程式除錯。

#error指令使前處理器發出一條錯誤訊息,該訊息包含指令中的文字.這條指令的目的就是在程式崩潰之前能夠給出一定的資訊。

#line        指令可以改變編譯器用來指出警告和錯誤資訊的檔案號和行號。#pragma  指令沒有正式的定義。編譯器可以自定義其用途。典型的用法是禁止或允許某些煩人的警告資訊。

#pragma

命令#pragma 為實現時定義的命令,它允許向編譯程式傳送各種指令。

#pragma的作用是設定編譯器的狀態或者是指示編譯器完成一些特定的動作。#pragma指令對每個編譯器給出了一個方法,在保持與C和C++語言完全相容的情況下,給出主機或作業系統專有的特徵。依據定義,編譯指示是機器或作業系統專有的,且對於每個編譯器都是不同的。

其格式一般為: #pragmapara

1message 引數。

 Message 引數能夠在編譯資訊輸出視窗中輸出相應的資訊,這對於原始碼資訊的控制是非常重要的。其使用方法為:

#pragma message(“訊息文字”)

當編譯器遇到這條指令時就在編譯輸出視窗中將訊息文字打印出來。

當我們在程式中定義了許多巨集來控制原始碼版本的時候,我們自己有可能都會忘記有沒有正確的設定這些巨集,此時我們可以用這條指令在編譯的時候就進行檢查。假設我們希望判斷自己有沒有在原始碼的什麼地方定義了_X86這個巨集可以用下面的方法

#ifdef _X86
#pragma message(“_X86 macro activated!”)
#endif


當我們定義了_X86這個巨集以後,應用程式在編譯時就會在編譯輸出窗口裡顯示“_

X86 macro activated!”。我們就不會因為不記得自己定義的一些特定的巨集而抓耳撓腮了。

2  code_seg 引數。

格式如:

#pragma code_seg(["section-name"[,"section-class"] ] )


它能夠設定程式中函式程式碼存放的程式碼段,當我們開發驅動程式的時候就會使用到它。

3#pragma once (比較常用)

只要在標頭檔案的最開始加入這條指令就能夠保證標頭檔案被編譯一次。這條指令實際上在VC6中就已經有了,但是考慮到相容性並沒有太多的使用它。

4#pragma hdrstop

表示預編譯標頭檔案到此為止,後面的標頭檔案不進行預編譯。BCB可以預編譯標頭檔案以加快連結的速度,但如果所有標頭檔案都進行預編譯又可能佔太多磁碟空間,所以使用這個選項排除一些標頭檔案。

有時單元之間有依賴關係,比如單元A依賴單元B,所以單元B要先於單元A編譯。你可以用#pragmastartup指定編譯優先順序,如果使用了#pragmapackage(smart_init) ,BCB就會根據優先順序的大小先後編譯。

5#pragma resource "*.dfm"

表示把*.dfm檔案中的資源加入工程。*.dfm中包括窗體外觀的定義。

6#pragma warning( disable : 4507 34; once : 4385; error : 164 )

等價於:

#pragma warning(disable:4507 34) /* 不顯示4507和34號警告資訊。如果編譯時總是出現4507號警告和34號警告, 而認為肯定不會有錯誤,可以使用這條指令。*/
#pragma warning(once:4385) // 4385號警告資訊僅報告一次
#pragma warning(error:164) // 把164號警告資訊作為一個錯誤。
同時這個pragmawarning 也支援如下格式:
#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 )


在這段程式碼的最後,重新儲存所有的警告資訊(包括4705,4706和4707)。

7pragma comment(...)

該指令將一個註釋記錄放入一個物件檔案或可執行檔案中。

常用的lib關鍵字,可以幫我們連入一個庫檔案。

8progma pack(n)

指定結構體對齊方式。#pragmapack(n)來設定變數以n位元組對齊方式。

n 位元組對齊就是說變數存放的起始地址的偏移量有兩種情況:

第一、如果n大於等於該變數所佔用的位元組數,那麼偏移量必須滿足預設的對齊方式,

第二、如果n小於該變數的型別所佔用的位元組數,那麼偏移量為n的倍數,不用滿足預設的對齊方式。

結構的總大小也有個約束條件,分下面兩種情況:如果n大於所有成員變數型別所佔用的位元組數,那麼結構的總大小必須為佔用空間最大的變數佔用的空間數的倍數;否則必須為n的倍數。

下面舉例說明其用法。

#pragma pack(push) //儲存對齊狀態
#pragma pack(4)//設定為4位元組對齊
struct test
{
char m1;
double m4;
int m3;
};
#pragma pack(pop)//恢復對齊狀態


為測試該功能,可以使用sizeof()測試結構體的長度!

預定義的巨集名
 
       ANSI C標準預定義了五個巨集名,每個巨集名的前後均有兩個下畫線,避免與程式設計師定義相同的巨集名(一般都不會定義前後有兩個下劃線的巨集)。這5個巨集名如下:

1

2

3

4

5

__DATE__:當前源程式的建立日期。

 __FILE__:當前源程式的檔名稱(包括碟符和路徑)。

__LINE__:當前被編譯程式碼的行號。

__STDC__:返回編譯器是否位標準C,若其值為1表示符合標準C,否則不是標準C.

__TIME__:當前源程式的建立時間。  

例子:

#include<stdio.h>
int main()
{
 int j;
printf("日期:%s\n",__DATE__);
printf("時間:%s\n",__TIME__};
printf("檔名:%s\n",__FILE__);
printf("這是第%d行程式碼\n",__LINE__);
printf("本編譯器%s標準C\n",(__STD__)?"符合":"不符合");
   return 0;
}


參考:

http://blog.chinaunix.net/uid-28458801-id-4424023.html

ps:一切內容均是本人根據網上各種途徑,翻閱書籍等方式總結提煉的,如果設計版權希望能及時提醒更改。同時希望注重保護他人成果!



相關推薦

c/c++處理過程條件編譯預定巨集

未經博主同意不得私自轉載!不準各種形式的貼上複製本文及盜圖! 首先對於上篇文章中巨集定義的補充: (1)#define NAME"zhangyuncong" 程式中有"NAME"則,它會不會被替換呢? (2)#define 0x abcd 可以嗎?也就是說,可不可以用不是

rpm包打包過程——製作原始碼安裝包

製作原始碼安裝包(.tar.gz) 1.      解決依賴的軟體: 系統環境:[紅帽企業Linux.6.4.64位伺服器版].rhel-server-6.4-x86_64 原始碼製作中使用到的軟體為GNU M4,GNU autoconf,GNU automake;GNU

Spring mvc請求處理流程檢視解析

前言   Spring mvc框架相信很多人都很熟悉了,關於這方面的資料也是一搜一大把。但是感覺講的都不是很細緻,讓很多初學者都雲裡霧裡的。本人也是這樣,之前研究過,但是後面一段時間不用發現又忘記了。所以決定寫下來,以備後用。   本系列文基於spring-

Android6.0 影象合成過程 doComposition函式

上篇部落格分析到setUpHWComposer函式,這裡我們繼續分析影象合成的過程從doComposition函式開始,以及在這過程中解答一些上篇部落格提出的疑問。 一、doComposition合成圖層 doComposition這個函式就是合成所有層的影象 void

ElasticSearch6.X版本Java Api中文Index Api解析

Inde API允許將型別化JSON文件索引到特定索引中,並使其可搜尋。生成JSON文件有幾種不同的方法:1.手動(也就是自己使用)使用本機位元組[]或作為字串。2.使用將自動轉換為其JSON等效的對映

實現螢幕切換、滑動-ViewPager--------PagerTitleStrip與PagerTabStrip新增標題欄

PagerTabStrip 1.PagerTabStrip概述:(API解釋) PagerTabStrip是ViewPager的一個關於當前頁面、上一個頁面和下一個頁面的一個非互動的指示器。它經常作為ViewPager控制元件的一個子控制元件被被新增

C語言處理命令

本文參考諸多資料,詳細介紹常用的幾種預處理功能。因成文較早,資料來源大多已不可考證,敬請諒解。全文字數2萬,閱讀時間50分鐘,建議先收藏。 一 前言 預處理(或稱預編譯)是指在進行編譯的第一遍掃描(詞法掃描和語法分析)之前所作的工作。預處理指令指示在程式正式編譯前就由編譯器進行的操作

C++ 模板

創建 規則 error ++ 例如 public err iostream () 四、類模板的默認模板類型形參   1、可以為類模板的類型形參提供默認值,但不能為函數模板的類型形參提供默認值。函數模板和類模板都可以為模板的非類型形參提供默認值。   2、類模板的類型形

C++ 智能指針

include 復雜 測試類 信息 思想 編譯 應該 其他 eas C++ 智能指針詳解 一、簡介 由於 C++ 語言沒有自動內存回收機制,程序員每次 new 出來的內存都要手動 delete。程序員忘記 delete,流程太復雜,最終導致沒有 delete,異常導致程

Python C API 使用

error 獲取 應該 tro pytho 都是 鍵值 字符 tin 簡介 介紹Python C API中的列表、元組、字典的使用,詳細的進行了API中方法的介紹。 Python List API List API 簡單介紹 int PyList_Check(PyObjec

C/C++ socket套接字Windows

一、編譯環境 本篇部落格是在windows系統下的CodeBlocks環境下編寫而成的,Linux系統以及其他編譯環境暫不適用 關於如何CodeBlocks如何安裝和配置/,可以參考連結(轉自螢火蟲塔莉):CodeBlocks的安裝以及編譯器的配置 常見問題: 編譯時不能識別socket

C++學習:list容器

list容器詳解       首先說說STL         STL就是Standard Template Library,標準模板庫。這可能是一個歷史上最令人興奮的工具的最無聊

c++:多型的理解

目錄 3抽象類 6物件模型 2:單繼承 3:多繼承 1多型概念: 通俗來講,就是多種形態,同一事物在不同場景下表現出的不同狀態。 2多型實現: c++的多型是在繼承的基礎上,增加了虛擬函式,並且讓派生

c++實戰開發類與物件

一、面向物件程式設計介紹 (一)什麼是面向物件?      面向將系統看成通過互動作用來完成特定功能的物件的集合。每個物件用自己的方法來管理資料。也就是說只有物件內部的程式碼能夠操作物件內部的資料。

C++模板

轉載自:http://www.cnblogs.com/gw811/archive/2012/10/25/2736224.html C++模板 四、類模板的預設模板型別形參   1、可以為類模板的型別形參提供預設值,但不能為函式模板的型別形參提供預設值。函式模板

嵌入式C++開發

面向物件程式設計(一) 一、面向物件程式設計介紹 (一)什麼是面向物件?       面向將系統看成通過互動作用來完成特定功能的物件的集合。每個物件用自己的方法來管理資料。也就是說只有物件內部的程式碼

C# 檔案操作FileInfo類

本篇讓我們一起看一下FileInfo類如何使用。     FileInfo類  提供了與File類相同的功能,不同的是FileInfo提供的都是成員方法   1、讀檔案 1 2 3 4 //摘要:建立只讀 System.IO.FileStrea

C++函式物件/偽函式Function Object

       除了自定義的函式物件,標準庫還為我們提供了一系列現成的函式物件, 比如常見的數學、邏輯運算等。例如:negate<type>(),plus<type>(),minus<type>(),multiplies<type&g

C#的反射技術

2。動態新增和使用型別反射提供了由語言編譯器(例如 Microsoft Visual Basic .NET 和 JScript)用來實現隱式晚期繫結的基礎結構。繫結是查詢與唯一指定的型別相對應的宣告(即實現)的過程。由於此過程在執行時而不是在編譯時發生,所以稱作晚期繫結。Vi

c++11多執行緒

  原文作者:aircraft 原文連結:https://www.cnblogs.com/DOMLX/p/10914162.html              最近是恰好寫了一些c++11多執行緒有關的東西,就寫一下筆記留著以後自己忘記回來看吧,也不是專門寫給讀者看的,我就想到哪就寫到哪吧 &nbs