1.什麼是宏定義?
引用自百度百科
宏(Macro),是一種批量處理的稱謂。計算機科學裏的宏是一種抽象(Abstraction),它根據一系列預定義的規則替換一定的文本模式。解釋器或編譯器在遇到宏時會自動進行這一模式替換。對於編譯語言,宏展開在編譯時發生,進行宏展開的工具常被稱爲宏展開器。宏這一術語也常常被用於許多類似的環境中,它們是源自宏展開的概念,這包括鍵盤宏和宏語言。絕大多數情況下,“宏”這個詞的使用暗示着將小命令或動作轉化爲一系列指令。
宏定義:是指用一個宏名(名字)來代表一個字符串。宏定義的功能是在編譯預處理時,對程序中所有出現的“宏名”都用宏定義中的字符串去代換,這稱爲“宏代換”或“宏展開”。
2.宏應用
1).宏定義常量
#define PI 3.1415926
#define PATH "D:\project\src"
2).宏定義表達式
#define MAX(a,b) ((a)<(b)?(b):(a))
注意:宏定義僅是做簡單的文本替換,如果是表達式需要用括號括起來,否則可能會出現邏輯上的“錯誤”
如下會得到意想不到的結果:
#include<stdio.h>
#define SUM(x, y) x + y //正確寫法是:#define SUM(x, y) ((x) + (y))
int main()
{
int a = 1, b = 2;
int sub = SUM(a, b) * SUM(a, b);
printf("sub = %d\n", sub);
return 0;
}
宏定義換行表達式(交換兩個整數值)
#define SWAP(x, y) \
{ \
int temp = x; \
x = y; \
y = temp; \
}
注意:宏定義行連接符是’\’
3.宏定義運用的好處與缺點
宏定義的好處:
1).提高代碼的可讀性,方便進行修改;
2).宏定義是簡單的文本替換,使用帶參的宏定義完成函數調用,可以提高程序的運行效率,減少系統開銷。
分析:宏是在預處理階段進行宏替換的,執行時不需要轉換,佔用編譯時間。並且宏定義不進行內存分配,由變量定義分配內存。(宏定義不存在類型問題,參數也是無類型的)
函數調用是在編譯後,程序運行時進行的,需要分配內存,值傳遞,返回值等一系列操作,佔用運行時間。
3).宏是由預處理器處理的,通過字符串操作可以完成很多編譯器無法實現的功能。比如##連接符。
宏定義缺點:
1).對帶參的宏而言,由於是直接替換,並不會檢查參數是否合法,存在安全隱患。
2).不方便調試問題。
4.什麼是條件編譯?
引用自百度百科
—般情況下,C語言源程序中的每一行代碼.都要參加編譯。但有時候出於對程序代碼優化的考慮.希望只對其中一部分內容進行編譯.此時就需要在程序中加上條件,讓編譯器只對滿足條件的代碼進行編譯,將不滿足條件的代碼捨棄,這就是條件編譯(conditional compile)。
5.條件編譯應用
三種語法格式:
1).if格式
#if 表達式
條件語句1
#else
條件語句2
#endif
當表達式的值爲真時,編譯條件語句1,否則編譯條件語句2。分支#else和條件語句2可以沒有。
2).ifdef格式
#ifdef 標識符
條件語句1
#else
條件語句2
#endif
當標識符已被定義時(用#define定義),編譯條件語句1,否則編譯條件語句2。分支#else和條件語句2可以沒有。
3).ifndef格式
#ifndef 標識符
條件語句1
#else
條件語句2
#endif
和ifdef格式相反(if not def)
6.#if(表達式)、#if defined(標識符) 和 #ifdef (標識符) 的區別
1).#if(表達式)後面跟的是表達式,條件爲真時,把條件語句編譯進去。
2).#if defined(標識符)後面跟的是宏定義,不管宏定義的標識符是真還是假,只要存在就把條件語句編譯進去。
3).#ifdef(標識符)和第二個用法一樣,但是隻能用於單個標識符,作爲判斷依據。
注意:如果是多個宏定義標識符作爲判斷依據,只能用defined()。
如:
#if (deined(A) || defined(B))
條件語句1
#endif
7.綜合引用
1).防止一個頭文件被重複包含
#ifndef _HELLO_H
#define _HELLO_H
#include<a.h>
#include<b.h>
int main();
#endif
當頭文件第一次被包含時,正常處理,符號_HELLO_H被定義爲1。如果頭文件被再次包含,通過條件編譯,它的內容被忽略。符號_HELLO_H按照被包含頭文件的文件名進行取名,以避免由於其他頭文件使用相同的符號而引起的衝突。
注意:預處理器仍將整個頭文件讀入,即使這個頭文件所有內容將被忽略。這種處理將託慢編譯速度,如果可能,應該避免出現多重包含。
#ifndef的是方式是受C/C++語言標準支持。#ifndef方式依賴於宏名稱要唯一。
優點:可以保證同一個文件不會被包含多次,也能保證內容完全相同的兩個文件不會被同時包含。
缺點:如果不同頭文件中的宏名不小心”碰撞”,可能就會導致你看到頭文件明明存在,編譯器卻硬說找不到聲明的狀況。由於編譯器每次都需要打開頭文件才能判定是否有重複定義,因此在編譯大型項目時,#ifndef會使得編譯時間相對較長。
另外一種處理方式#pragma once
#pragma once
#include<a.h>
#include<b.h>
int main();
#pragma once由編譯器提供保證:
同一個文件名不會被包含多次。無法對一個頭文件中的一段代碼作#pragma once聲明,只能針對文件。
優點:不會出現宏名一樣引發的奇怪問題,大型項目的編譯速度也因此得以提高。
缺點:如果某個頭文件有多份拷貝,此方法不能保證它們不被重複包含。在C/C++中,#pragma once是一個非標準但是被廣泛支持的方式。