C 預(yù)處理

2018-05-20 16:35 更新

學(xué)習(xí)C - C預(yù)處理

源代碼的預(yù)處理發(fā)生在編譯為機(jī)器指令之前。

預(yù)處理階段可以執(zhí)行由#符號(hào)啟動(dòng)的預(yù)處理指令指定的操作范圍。

預(yù)處理階段在編譯之前處理C源代碼。

在預(yù)處理階段后,將分析和執(zhí)行所有指令,并且所有預(yù)處理指令將不再出現(xiàn)在源代碼中。

#include #define 是兩個(gè)流行的指令。

用#define語(yǔ)句定義常量。


#include <stdio.h> 
#define PI 3.14159
int main(void) 
{ 
    float area, circum, radius; 
 
    printf("What is the radius of your pizza?\n"); 
    scanf("%f", &radius); 
    area = PI * radius * radius; 
    circum = 2.0 * PI *radius; 
    printf("Your basic pizza parameters are as follows:\n"); 
    printf("circumference = %1.2f, area = %1.2f\n", circum, 
           area); 
    return 0; 
}    

上面的代碼生成以下結(jié)果。



包括頭文件

你完全熟悉這樣的語(yǔ)句:

#include <stdio.h>

上面的代碼將標(biāo)準(zhǔn)庫(kù)頭文件的內(nèi)容帶入您的程序。

#include指令引入到程序中的文件也可能包含#include指令。

定義頭文件

您可以定義自己的頭文件,通常使用擴(kuò)展名為.h。

頭文件不應(yīng)包括實(shí)現(xiàn)。

您創(chuàng)建頭文件以包含聲明。

所有的函數(shù)定義和全局變量都放在擴(kuò)展名為.c的源文件中。

您可以將函數(shù)原型,結(jié)構(gòu)類型定義,符號(hào)定義,extern語(yǔ)句和typedefs放在頭文件中。
一個(gè)典型的例子可能是:

#include "myfile.h"

外部變量

要使用另一個(gè)文件的全局變量,請(qǐng)使用extern關(guān)鍵字將該變量聲明為當(dāng)前源文件的外部變量。

例如,假設(shè)您的語(yǔ)句在另一個(gè)文件中定義了全局變量:

int number = 0; 
double in_to_mm = 2.54; 

在要訪問這些文件的源文件中,指定這些變量名稱是外部的:

extern int number; 
extern double in_to_mm; 

這些語(yǔ)句不會(huì)創(chuàng)建這些變量。

他們通知編譯器這些名稱被定義在哪里。


靜態(tài)函數(shù)

您可以通過將其聲明為靜態(tài)來(lái)確保函數(shù)僅在您定義它的源文件中可見。

例如:

static double average(double x, double y) { return (x + y) / 2.0; }

程序源代碼中的替換

define預(yù)處理器指令的一般形式如下:

#define identifier sequence_of_characters 

這里,標(biāo)識(shí)符符合C中標(biāo)識(shí)符的通常定義。

在#define語(yǔ)句中定義字符串。


#include <stdio.h> 
#define PRAISE "You are an extraordinary being." 
int main(void) 
{ 
    char name[40]; 
 
    printf("What"s your name? "); 
    scanf("%s", name); 
    printf("Hello, %s. %s\n", name, PRAISE); 
 
    return 0; 
}    

上面的代碼生成以下結(jié)果。

宏是預(yù)處理器,允許可以稱為多個(gè)參數(shù)化替換。

這涉及到用于令牌標(biāo)識(shí)符的字符序列的替換。

一個(gè)例子將使這更容易理解:

#define Print(My_var) printf_s("%d", My_var) 

My_var 是一個(gè)參數(shù)名稱,可以指定一個(gè)字符串。

該指令提供兩個(gè)替代級(jí)別。

代碼中的Print(My_var)的出現(xiàn)將被緊隨其后的字符串以及您為My_var指定的任何參數(shù)所代替。

例如,你可以寫下列內(nèi)容:

Print(ival);

這將在預(yù)處理期間轉(zhuǎn)換為此語(yǔ)句:

printf_s("%d", ival);

宏函數(shù)

剛才討論的替代方式的一般形式如下:

#define macro_name( list_of_identifiers ) substitution_string

以下代碼顯示了如何使用以下指令定義最多生成兩個(gè)值的宏:

#define max(x, y) x>y ? x : y

然后,您可以將該語(yǔ)句放在程序中:

int result = max(myval, 99);

這將在預(yù)處理期間擴(kuò)展,以生成以下代碼:

int result = myval>99 ? myval : 99; 

條件編譯

由于在先前的#define指令中已創(chuàng)建標(biāo)識(shí)符,因此我們可以測(cè)試是否存在標(biāo)識(shí)符。

它采取以下形式:

#if defined identifier 
// Statements... 
#endif 

如果指定的標(biāo)識(shí)符在此之前由#define指令定義,則#if之后的語(yǔ)句將包含在程序代碼中,直到指令#endif為止。

如果未定義標(biāo)識(shí)符,則#if和#endif之間的語(yǔ)句將被跳過。

您可以測(cè)試缺少標(biāo)識(shí)符。

該指令的一般形式是:

#if !defined identifier 
// Statements... 
#endif 

這里,如果以前沒有定義標(biāo)識(shí)符,那么#if下面的#endif之后的語(yǔ)句將被包含。

這可以避免重復(fù)的功能或其他代碼和指令。

這個(gè)機(jī)制只是把你想避免重復(fù)的代碼塊的頂部和尾部如下所示:

#if !defined block1 
  #define block1 
  /* Statements you do not          */ 
  /* want to occur more than once.  */ 
#endif 

測(cè)試多個(gè)條件

您可以使用邏輯運(yùn)算符來(lái)測(cè)試是否定義了多個(gè)標(biāo)識(shí)符。例如:

#if defined block1 && defined block2 
   // Statements... 
#endif 

如果先前已經(jīng)定義了block1和block2,則此值將為true。

您可以使用||和!運(yùn)算符結(jié)合&&。

未定義標(biāo)識(shí)符

我們可以取消定義您之前定義的標(biāo)識(shí)符。

這是使用指令實(shí)現(xiàn)的,例如:

#undef block1

如果先前定義了block1,則該指令不再被定義。

測(cè)試標(biāo)識(shí)符的特定值

您可以使用#if指令的形式來(lái)測(cè)試常量表達(dá)式的值。

如果常量表達(dá)式的值不為零,則下列語(yǔ)句直到下一個(gè)#endif包含在程序代碼中。

如果常量表達(dá)式計(jì)算為零,則會(huì)跳過下一個(gè)#endif的下一個(gè)語(yǔ)句。

#if指令的一般形式是:

#if constant_expression

您可能會(huì)有以下語(yǔ)句序列,例如:

#if CPU == Intel
  printf("Performance should be good.\n" ); 
#endif 

多重選擇

你有#else指令。

如果#if條件失敗,它會(huì)標(biāo)識(shí)要執(zhí)行的一組指令或要包括的語(yǔ)句,例如:

#if CPU == Intel
  printf_s("Performance should be good.\n" ); 
#else 
  printf_s("Performance may not be so good.\n" ); 
#endif 

#elif指令具??有一般形式:

#elif constant_expression

標(biāo)準(zhǔn)預(yù)處理宏

__DATE__宏會(huì)以Mmm dd yyyy格式生成日期的字符串表示形式。

這里Mmm是個(gè)月,如1月,2月等等。

一對(duì)字符dd是一對(duì)數(shù)字1到31的形式,其中單位數(shù)字前面有一個(gè)空格。

最后,例如,yyyy是2012年的四位數(shù)字。

__TIME__提供一個(gè)包含時(shí)間值的字符串,格式為hh:mm:ss。

時(shí)間是編譯器執(zhí)行時(shí),而不是當(dāng)程序運(yùn)行時(shí)。

當(dāng)您的程序上次使用此語(yǔ)句進(jìn)行編譯時(shí),可以使用此宏來(lái)記錄輸出:

printf_s("Program last compiled at %s on %s\n", __TIME__, __DATE__ );

執(zhí)行此語(yǔ)句將產(chǎn)生類似于以下內(nèi)容的輸出:

Program last compiled at 15:27:01 on Nov 24 2015 

__FILE__宏將當(dāng)前源文件的名稱表示為字符串文字。

__LINE__宏包含與當(dāng)前行號(hào)相對(duì)應(yīng)的整數(shù)常量。

您可以結(jié)合使用__FILE__宏來(lái)識(shí)別源代碼中哪個(gè)特定事件或錯(cuò)誤已被檢測(cè)到。

例如:

fprintf(stderr, "Failed to open file in %s line %d\n", __FILE__, __LINE__);
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)