C/C++學習筆記——C提高:預處理

預處理的基本概念

C語言對源程序處理的四個步驟:預處理、編譯、彙編、鏈接。
預處理是在程序源代碼被編譯之前,由預處理器(Preprocessor)對程序源代碼進行的處理。這個過程並不對程序的源代碼語法進行解析,但它會把源代碼分割或處理成爲特定的符號爲下一步的編譯做準備工作。

文件包含指令(#include)

文件包含處理

“文件包含處理”是指一個源文件可以將另外一個文件的全部內容包含進來。C語言提供了#include命令用來實現“文件包含”的操作。

#incude<>和#include""區別

  • “” 表示系統先在file1.c所在的當前目錄找file1.h,如果找不到,再按系統指定的目錄檢索。
  • < > 表示系統直接按系統指定的目錄檢索。
    注意:
    1. #include <>常用於包含庫函數的頭文件;
    2. #include ""常用於包含自定義的頭文件;
    3. 理論上#include可以包含任意格式的文件(.c .h等) ,但一般用於頭文件的包含;

宏定義

無參數的宏定義(宏常量)

如果在程序中大量使用到了100這個值,那麼爲了方便管理,我們可以將其定義爲:
const int num = 100; 但是如果我們使用num定義一個數組,在不支持c99標準的編譯器上是不支持的,因爲num不是一個編譯器常量,如果想得到了一個編譯器常量,那麼可以使用:
#define num 100
在編譯預處理時,將程序中在該語句以後出現的所有的num都用100代替。這種方法使用戶能以一個簡單的名字代替一個長的字符串,在預編譯時將宏名替換成字符串的過程稱爲“宏展開”。宏定義,只在宏定義的文件中起作用。

#define PI 3.1415
void test(){
	double r = 10.0;
	double s = PI * r * r;
	printf("s = %lf\n", s);
}

說明:

  1. 宏名一般用大寫,以便於與變量區別;
  2. 宏定義可以是常數、表達式等;
  3. 宏定義不作語法檢查,只有在編譯被宏展開後的源程序纔會報錯;
  4. 宏定義不是C語言,不在行末加分號;
  5. 宏名有效範圍爲從定義到本源文件結束;
  6. 可以用#undef命令終止宏定義的作用域;
  7. 在宏定義中,可以引用已定義的宏名;

帶參數的宏定義(宏函數)

在項目中,經常把一些短小而又頻繁使用的函數寫成宏函數,這是由於宏函數沒有普通函數參數壓棧、跳轉、返回等的開銷,可以調高程序的效率。

宏通過使用參數,可以創建外形和作用都與函數類似地類函數宏(function-like macro). 宏的參數也用圓括號括起來。

#define SUM(x,y) ((x)+(y))
void test(){
	
	//僅僅只是做文本替換 下例替換爲 int ret = ((10)+(20));
	//不進行計算
	int ret = SUM(10, 20);
	printf("ret:%d\n",ret);
}

注意:

  1. 宏的名字中不能有空格,但是在替換的字符串中可以有空格。ANSI C允許在參數列表中使用空格;
  2. 用括號括住每一個參數,並括住宏的整體定義。
  3. 用大寫字母表示宏的函數名。
  4. 如果打算宏代替函數來加快程序運行速度。假如在程序中只使用一次宏對程序的運行時間沒有太大提高。

條件編譯

基本概念

一般情況下,源程序中所有的行都參加編譯。但有時希望對部分源程序行只在滿足一定條件時才編譯,即對這部分源程序行指定編譯條件。
在這裏插入圖片描述

條件編譯

  • 防止頭文件被重複包含引用;
#ifndef _SOMEFILE_H
#define _SOMEFILE_H

//需要聲明的變量、函數
//宏定義
//結構體

#endif

一些特殊的預定宏

C編譯器,提供了幾個特殊形式的預定義宏,在實際編程中可以直接使用,很方便。

//	__FILE__			宏所在文件的源文件名 
//	__LINE__			宏所在行的行號
//	__DATE__			代碼編譯的日期
//	__TIME__			代碼編譯的時間

void test()
{
	printf("%s\n", __FILE__);
	printf("%d\n", __LINE__);
	printf("%s\n", __DATE__);
	printf("%s\n", __TIME__);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章