武漢電腦培訓(xùn)資訊:【武漢華嵌】關(guān)于高級編譯預(yù)處理的幾種用法

武漢
當前位置:求學(xué)問校網(wǎng)首頁>武漢資訊>武漢電腦培訓(xùn)資訊

【武漢華嵌】關(guān)于高級編譯預(yù)處理的幾種用法

來源:求學(xué)問校網(wǎng)     發(fā)表時間:2011-12-09     瀏覽 59

作者:武漢華嵌技術(shù)部

 

C程序的源代碼中可包括各種編譯指令,這些指令稱為預(yù)處理命令。雖然它們實際上不是C語言的一部分,但卻擴展了C程序設(shè)計的環(huán)境。本節(jié)將介紹如何應(yīng)用預(yù)處理程序和注釋簡化程序開發(fā)過程,并提高程序的可讀性。

 

一、C宏體中出現(xiàn)的#,#@,##:

1、#的功能是將其后面的宏參數(shù)進行字符串化操作(Stringfication)
2、##被稱為連接符(concatenator),用來將兩個Token連接為一個Token。
3、#@的功能是將其后面的宏參數(shù)進行字符化。

以下是應(yīng)用的代碼:

#include <stdio.h>

#define Conn(x,y) x##y

#define ToChar(a) #@a

#define ToString(x) #x

int main()

{

      int a = Conn(1ƺ);

      printf("%d\n", a);

      printf("%c\n", ToChar(4));

      printf(ToString(45678\n));

      return 0;

}

輸出結(jié)果為:

      12

      4

      45678

 

以下是UBOOT中的一部分源代碼:

#define U_BOOT_CMD(name, maxargs, rep, cmd, usage, help)\

cmd_tbl_t         u_boot_cmd_##name     Struct_Section = {#name, maxargs, rep, cmd, usage}

 

 

二、#pragma  pack()的使用:

      在所有的預(yù)處理指令中,#pragma 指令可能是最復(fù)雜的了,它的作用是設(shè)定編譯器的狀態(tài)或者是指示編譯器完成一些特定的動作。#pragma指令對每個編譯器給出了一個方法,在保持與C和C ++語言完全兼容的情況下,給出主機或操作系統(tǒng)專有的特征。依據(jù)定義,編譯指示是機器或操作系統(tǒng)專有的,且對于每個編譯器都是不同的。

其格式一般為:#pragma para,其中para為參數(shù),下面來看一些常用的參數(shù)。

#pragma pack規(guī)定的對齊長度,什么是對齊,以及為什么要對齊:現(xiàn)代計算機中內(nèi)存空間都是按照byte劃分的,從理論上講似乎對任何類型的變量的訪問可以從任何地址開始,但實際情況是在訪問特定變量的時候經(jīng)常在特定的內(nèi)存地址訪問,這就需要各類型數(shù)據(jù)按照一定的規(guī)則在空間上排列,而不是順序的一個接一個的排放,這就是對齊。對齊的作用和原因:各個硬件平臺對存儲空間的處理上有很大的不同。一些平臺對某些特定類型的數(shù)據(jù)只能從某些特定地址開始存取。其他平臺可能沒有這種情況,但是最常見的是如果不按照適合其平臺要求對數(shù)據(jù)存放進行對齊,會在存取效率上帶來損失。比如有些平臺每次讀都是從偶地址開始,如果一個int型(假設(shè)為32位系統(tǒng))如果存放在偶地址開始的地方,那么一個讀周期就可以讀出,而如果存放在奇地址開始的地方,就可能會需要2個讀周期,并對兩次讀出的結(jié)果的高低字節(jié)進行拼湊才能得到該int數(shù)據(jù)。顯然在讀取效率上下降很多。這也是空間和時間的博弈。對齊的實現(xiàn)通常,我們寫程序的時候,不需要考慮對齊問題。編譯器會替我們選擇時候目標平臺的對齊策略。當然,我們也可以通知給編譯器傳遞預(yù)編譯指令而改變對指定數(shù)據(jù)的對齊方法。但是,正因為我們一般不需要關(guān)心這個問題,所以因為編輯器對數(shù)據(jù)存放做了對齊,而我們不了解的話,常常會對一些問題感到迷惑。最常見的就是struct數(shù)據(jù)結(jié)構(gòu)的sizeof結(jié)果,出乎意料。為此,我們需要對對齊算法所了解。

作用:指定結(jié)構(gòu)體、聯(lián)合以及類成員的packing alignment;

語法:#pragma pack( [show] | [push | pop] [, identifier], n )

#pragma pack(n)來設(shè)定變量以n字節(jié)對齊方式。n字節(jié)對齊就是說變量存放的起始地址的偏移量有兩種情況:第一、如果n大于等于該變量所占用的字節(jié)數(shù),那么偏移量必須滿足默認的對齊方式,第二、如果n小于該變量的類型所占用的字節(jié)數(shù),那么偏移量為n的倍數(shù),不用滿足默認的對齊方式。結(jié)構(gòu)的總大小也有個約束條件,分下面兩種情況:如果n大于所有成員變量類型所占用的字節(jié)數(shù),那么結(jié)構(gòu)的總大小必須為占用空間最大的變量占用的空間數(shù)的倍數(shù);

  #pragma pack(push) //保存對齊狀態(tài)

  #pragma pack(2)//設(shè)定為2字節(jié)對齊

  struct test

  {

     char a;

     int b;

     char c;

  };

#pragma pack(pop)//恢復(fù)原先的對齊狀態(tài)

以上結(jié)構(gòu)體的大小為8,下面分析其存儲情況,首先為a分配空間,其偏移量為0,滿足我們自己設(shè)定的對齊方式(2字節(jié)對齊),a大小為1個字節(jié)。接著開始為b分配空間,這時其偏移量為2,需要補足1個字節(jié),這樣使偏移量滿足為n=2的倍數(shù)(因為sizeof(int)大于4),b占用4個字節(jié)。接著為c分配空間,這時其偏移量為6,滿足為2的倍數(shù),c占用1個字節(jié)。這時已經(jīng)為所有成員變量分配了空間,共分配了8個字節(jié),滿足為2的倍數(shù)。如果把上面的#pragma pack(2)改為#pragma pack(4),那么我們可以得到結(jié)構(gòu)的大小為12。