天天看點

c語言宏定義在預處理階段,預處理和宏定義

c語言宏定義在預處理階段,預處理和宏定義

8種機械鍵盤軸體對比

本人程式員,要買一個寫代碼的鍵盤,請問紅軸和茶軸怎麼選?

宏定義

基本概念預處理部分: #include #define 放在函數之外,一般都放在源文檔的前面

預處理由預處理程序負責,當對一個源文檔進行編譯時,系統将自動引用預處理程序對源程序中的預處理部分作處理,處理完畢将自動進入對源程序的編譯。

C語言提供了多種預處理功能,如宏定義、文檔包含、條件編譯等。

不帶參數的宏定義被定義為 宏 的辨別符稱為 宏名。 在編譯階段對程序中所有出現的 宏名 都用宏定義中的字元串去代換

宏定義由源程序中的宏定義指令完成的。宏代換是由預處理程序自動完成的。

c語言中 宏分為 有參數 和無參數兩種。1

2

3

4

5

6

7#define 辨別符 字元串

以 # 開頭的均為預處理指令

define 為預處理指令

辨別符 為所定義的宏名

字元串 可以是常數、表達式、格式串等

宏使用時的注意事項習慣上宏名用大寫字母表示,以便于與變量差別,但是也允許使用小寫字母

宏定義是用宏名表示一個字元串(可以是任何字元,常數,表達式),在宏展開時又以該字元串取代宏名。

預處理程序不做檢查,在宏展開編譯的時候發現

宏定義不是說明或語句,末尾不用加 分号“;” 加“;” 連同“;”一起置換

宏定義必須寫在函數之外,預設的有效區到源程序結束, 要是提前結束 使用 #undef 指令1

2#undef PI

宏名在源程序中使用雙引号括起來,則預處理程序不對其作宏代換1

2

3

4

5

6

7#define H "hello world"

int main(){

printf(H);

printf("n%sn",H);

printf("Hn"); // H

}

宏定義允許嵌套,在宏展開時由預處理程序層層代換1

2

3#define PI 3.1415926

#define R 5

#define SUM 2*PI*R

可用宏定義表示資料類型,使書寫友善

對輸出格式做宏定義,減少書寫麻煩

#define 和 typedef的差別注意用宏定義表示資料類型和用typedef定義資料說明符的差別。宏定義隻是簡單的字元串代換,是在預處理完成的,而typedef是在編譯時處理的,不是作簡單的代換,而是對類型說明符重新命名,被命名的辨別符具有類型定義說明的功能。1

2

3

4

5

6

7

8

9

10#define PIN1 int *

typedef int * PIN2;

PIN1 a,b

a = &m; // OK int *a; a = &m;

b = &n; // ERROE int b; b = &n;

PIN2 c,d;

c = &m; // OK int *c; c = &m;

d = &n; // OK int *d; d = &n;

帶有參數的宏定義有參宏的定義方法

C語言中允許帶有參數,在宏定義中的參數成為形式參數,在宏調用中的參數稱為實際參數。

對帶參數的宏,在調用中,不僅要宏展開,而且要用實參去代換形參。1

2

3

4

5

6

7

8

9

10

11// 帶參數的宏定義的一般形式為:

#define 宏名(形參表) 字元串

// 帶參宏調用的一般形式為:

宏名(實參表)

eg:

// 宏定義

#define M(y) y*y+3*y

// 宏調用

M(5);

有參宏的注意事項帶參宏定義中,形參之間可以出現空格,但是宏名和形參表之間不能有空格出現。

帶參宏定義中,形參不配置設定記憶體單元,實參有具體值,必須作類型說明,帶參宏定義隻是符号代換,不存在值傳遞。而函數中形參和實參是兩個不同的量,有各自的作用域,調用時進行 值傳遞

在宏定義中形參是辨別符,而宏調用中的實參可以是表達式

在宏定義中,字元串中的形參通常要用括号括起來避免出錯。

宏定義可以用來定義多個語句。在宏調用時,把這些語句又代換到源程序内。

條件編譯

為什麼要用條件編譯?按不同條件去編譯不同的程序部分,因而産生不同的目标代碼文檔。有利于程序的移植和調試。

可以使用條件語句來實作條件編譯。1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28// 第一種形式

#if 常量表達式

程序段1

#elif

程序段2

#else

程序段3

#endif

條件編譯後面的表達式中不能出現變量,隻能識别常量和宏定義

// 第二種形式

#ifdef 辨別符

程序段1

#else

程序段2

#elseif

// 如果辨別符已被#define指令定義過則對程序段1進行編譯;否則對程序段2進行編譯。

// 第三種形式

#ifndef 辨別符

程序段1

#else

程序段2

#endif

// 如果辨別符未被 #define 指令定義, 則對程序段1進行編譯,否則對程序段2進行編譯。

預處理

什麼是預處理?以 # 開頭的代碼行

#号必須是該行除了任何空白字元外的第一個字元。

#後是指令關鍵字,在關鍵字和#号之間允許存在任意個數的空白字元。

整行語句構成了一條預處理指令,該指令将在編譯器進行編譯之前對源代碼做某些轉換

常見的預處理指令指令說明#空指令,無任何效果

#include包含一個源代碼文檔

#define定義宏

#undef取消已定義的宏

#if如果給定條件為真,編譯下面的代碼

#ifdef如果宏已經定義,編譯下面的代碼

#ifndef如果宏沒有定義,編譯下面的代碼

#elif#if不為真,目前條件為真,編譯下面的代碼

#endif結束條件編譯塊

static和extern的使用它們都是用來修飾變量(局部的static實際也是全局)

static修飾的變量 隻有你的包含那個變量定義的源代碼文檔可以通路

extern定義的變量 是任何一個源文檔都可以通路,隻要聲明了就可以

static與extern對局部變量的作用static對局部變量的作用延長局部變量的生命周期,從程序啟動到程序退出,但是它沒有改變 變量的 作用域

定義變量的代碼在整個程序運作期間僅僅會執行一次1

2

3

4

5

6

7

8

9

10

11

12

13

14void add(){

static int a = 10; // int a = 10;

a++;

printf("a++: %dn",a);

}

int main() {

add(); // 11

add(); // 12

add(); // 13

return 0;

}

// extern 不是定義局部變量,它是在函數内部聲明的全局變量

static與extern對全局變量的作用全局變量内部變量:隻能在本文檔中通路的變量

外部變量:可以在其他中通路的變量,預設所有全局變量都是外部變量static作用聲明一個内部變量

定義一個内部變量

注意:在不同文檔中可以定義同名的内部變量如果聲明的時候沒有寫extern那系統會自動定義這個變量,并将其初始化為0

如果你使用extern來聲明一個變量,如果沒有你定義的,那麼系統就會報錯

static與extern對函數的作用内部函數: 在A文檔中定義的函數,在A文檔中通路

外部函數: 在B文檔中通路A文檔中定義的函數,函數在B中稱之為外部函數

全局變量&局部變量常見問題

局部變量能否和全局變量重名?能,局部會屏蔽全局,要用全局變量,需要使用”::”(域運算符)

如何引用一個已經定義過的全局變量?extern, 可以用引用頭文檔的方式,也可以用extern關鍵字,使用引入頭文檔方式(有錯誤會在編譯階段報錯),使用extern方式引用時(有錯誤會在連接配接期間報錯)

全局變量可以定義在被多個.c文檔包含的頭文檔中?可以,在不同的C文檔中以static形式來聲明同名全局變量

static全局變量和普通的全局變量差別static全局變量隻初始化一次,防止在其他文檔單元中被引用.

static局部變量和普通的局部變量差別static局部變量隻被初始化一次,下一次依據上一次的結果值.

static函數和普通函數差別static函數在記憶體中隻有一份,普通函數在每個被調用中維持一份拷貝.

程序的局部變量存在于(堆棧)中,全局變量存在于(靜态區)中,動态申請資料存在于(堆)中