源代碼的預處理發(fā)生在編譯為機器指令之前。
預處理階段可以執(zhí)行由#
符號啟動的預處理指令指定的操作范圍。
預處理階段在編譯之前處理C源代碼。
在預處理階段后,將分析和執(zhí)行所有指令,并且所有預處理指令將不再出現(xiàn)在源代碼中。
#include
和 #define
是兩個流行的指令。
用#define語句定義常量。
#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é)果。
你完全熟悉這樣的語句:
#include <stdio.h>
上面的代碼將標準庫頭文件的內(nèi)容帶入您的程序。
#include指令引入到程序中的文件也可能包含#include指令。
您可以定義自己的頭文件,通常使用擴展名為.h。
頭文件不應包括實現(xiàn)。
您創(chuàng)建頭文件以包含聲明。
所有的函數(shù)定義和全局變量都放在擴展名為.c的源文件中。
您可以將函數(shù)原型,結(jié)構(gòu)類型定義,符號定義,extern語句和typedefs放在頭文件中。
一個典型的例子可能是:
#include "myfile.h"
要使用另一個文件的全局變量,請使用extern關(guān)鍵字將該變量聲明為當前源文件的外部變量。
例如,假設(shè)您的語句在另一個文件中定義了全局變量:
int number = 0; double in_to_mm = 2.54;
在要訪問這些文件的源文件中,指定這些變量名稱是外部的:
extern int number; extern double in_to_mm;
這些語句不會創(chuàng)建這些變量。
他們通知編譯器這些名稱被定義在哪里。
您可以通過將其聲明為靜態(tài)來確保函數(shù)僅在您定義它的源文件中可見。
例如:
static double average(double x, double y) { return (x + y) / 2.0; }
define預處理器指令的一般形式如下:
#define identifier sequence_of_characters
這里,標識符符合C中標識符的通常定義。
在#define語句中定義字符串。
#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é)果。
宏是預處理器,允許可以稱為多個參數(shù)化替換。
這涉及到用于令牌標識符的字符序列的替換。
一個例子將使這更容易理解:
#define Print(My_var) printf_s("%d", My_var)
My_var
是一個參數(shù)名稱,可以指定一個字符串。
該指令提供兩個替代級別。
代碼中的Print(My_var)的出現(xiàn)將被緊隨其后的字符串以及您為My_var指定的任何參數(shù)所代替。
例如,你可以寫下列內(nèi)容:
Print(ival);
這將在預處理期間轉(zhuǎn)換為此語句:
printf_s("%d", ival);
剛才討論的替代方式的一般形式如下:
#define macro_name( list_of_identifiers ) substitution_string
以下代碼顯示了如何使用以下指令定義最多生成兩個值的宏:
#define max(x, y) x>y ? x : y
然后,您可以將該語句放在程序中:
int result = max(myval, 99);
這將在預處理期間擴展,以生成以下代碼:
int result = myval>99 ? myval : 99;
由于在先前的#define指令中已創(chuàng)建標識符,因此我們可以測試是否存在標識符。
它采取以下形式:
#if defined identifier // Statements... #endif
如果指定的標識符在此之前由#define指令定義,則#if之后的語句將包含在程序代碼中,直到指令#endif為止。
如果未定義標識符,則#if和#endif之間的語句將被跳過。
您可以測試缺少標識符。
該指令的一般形式是:
#if !defined identifier // Statements... #endif
這里,如果以前沒有定義標識符,那么#if下面的#endif之后的語句將被包含。
這可以避免重復的功能或其他代碼和指令。
這個機制只是把你想避免重復的代碼塊的頂部和尾部如下所示:
#if !defined block1 #define block1 /* Statements you do not */ /* want to occur more than once. */ #endif
您可以使用邏輯運算符來測試是否定義了多個標識符。例如:
#if defined block1 && defined block2 // Statements... #endif
如果先前已經(jīng)定義了block1和block2,則此值將為true。
您可以使用||和!運算符結(jié)合&&。
我們可以取消定義您之前定義的標識符。
這是使用指令實現(xiàn)的,例如:
#undef block1
如果先前定義了block1,則該指令不再被定義。
您可以使用#if指令的形式來測試常量表達式的值。
如果常量表達式的值不為零,則下列語句直到下一個#endif包含在程序代碼中。
如果常量表達式計算為零,則會跳過下一個#endif的下一個語句。
#if指令的一般形式是:
#if constant_expression
您可能會有以下語句序列,例如:
#if CPU == Intel printf("Performance should be good.\n" ); #endif
你有#else指令。
如果#if條件失敗,它會標識要執(zhí)行的一組指令或要包括的語句,例如:
#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
__DATE__宏會以Mmm dd yyyy格式生成日期的字符串表示形式。
這里Mmm是個月,如1月,2月等等。
一對字符dd是一對數(shù)字1到31的形式,其中單位數(shù)字前面有一個空格。
最后,例如,yyyy是2012年的四位數(shù)字。
__TIME__提供一個包含時間值的字符串,格式為hh:mm:ss。
時間是編譯器執(zhí)行時,而不是當程序運行時。
當您的程序上次使用此語句進行編譯時,可以使用此宏來記錄輸出:
printf_s("Program last compiled at %s on %s\n", __TIME__, __DATE__ );
執(zhí)行此語句將產(chǎn)生類似于以下內(nèi)容的輸出:
Program last compiled at 15:27:01 on Nov 24 2015
__FILE__宏將當前源文件的名稱表示為字符串文字。
__LINE__宏包含與當前行號相對應的整數(shù)常量。
您可以結(jié)合使用__FILE__宏來識別源代碼中哪個特定事件或錯誤已被檢測到。
例如:
fprintf(stderr, "Failed to open file in %s line %d\n", __FILE__, __LINE__);
更多建議: