【C語言】23-typedef


說明:這個C語言專題,是學習iOS開發的前奏。也為了讓有面向對象語言開發經驗的程序員,能夠快速上手C語言。如果你還沒有編程經驗,或者對C語言、iOS開發不感興趣,請忽略

這講介紹C語言中很常用的一個關鍵字---typedef

一、typedef作用簡介

* 我們可以使用typedef關鍵字為各種數據類型定義一個新名字(別名)。

 1 #include <stdio.h>
 2 
 3 typedef int Integer;
 4 typedef unsigned int UInterger;
 5 
 6 typedef float Float;
 7 
 8 int main(int argc, const char * argv[]) {
 9     Integer i = -10;
10     UInterger ui = 11;
11     
12     Float f = 12.39f;
13     
14     printf("%d  %d  %.2f", i, ui, f);
15     
16     return 0;
17 }

 在第3、第4、第6行分別給int、unsigned int、float起了個別名,然后在main函數中使用別名定義變量,用來跟原來的基本類型是完全一樣的。輸出結果:

當然,給類型起別名后,原來的int、float還是可以正常使用的:

int i = 10;

float f = 10.0f;

 

* 也可以在別名的基礎上再起一個別名

typedef int Integer;

typedef Integer MyInteger;

 

二、typedef與指針

除開可以給基本數據類型起別名,typedef也可以給指針起別名

 1 #include <stdio.h>
 2 
 3 typedef char *String;
 4 
 5 int main(int argc, const char * argv[]) {
 6     // 相當於char *str = "This is a string!";
 7     String str = "This is a string!";
 8     
 9     printf("%s", str);
10     
11     return 0;
12 }

在第3給指針類型char *起別名為String,然后在第7行使用String定義了一個字符串,是不是有點Java的感覺?

 

三、typedef與結構體

給結構體起別名可以使代碼更加簡潔明

1.默認情況下結構體變量的使用

 1 // 定義一個結構體
 2 struct MyPoint {
 3     float x;
 4     float y;
 5 };
 6 
 7 int main(int argc, const char * argv[]) {
 8     // 定義結構體變量
 9     struct MyPoint p;
10     p.x = 10.0f;
11     p.y = 20.0f;
12     
13     return 0;
14 }

默認情況下,我們定義結構體變量需要帶個struct關鍵字,看第9行

 

2.使用typedef給結構體起別名

 1 // 定義一個結構體
 2 struct MyPoint {
 3     float x;
 4     float y;
 5 };
 6 
 7 // 起別名
 8 typedef struct MyPoint Point;
 9 
10 int main(int argc, const char * argv[]) {
11     // 定義結構體變量
12  Point p;
13     p.x = 10.0f;
14     p.y = 20.0f;
15     
16     return 0;
17 }

我們在第8行給結構體MyPoint起了個別名叫做Point,然后在12行使用Point定義了一個結構體變量p,不用再帶上struct關鍵字了

其實第1~第8行的代碼可以簡寫為:

// 定義一個結構體,順便起別名
typedef struct MyPoint {
    float x;
    float y;
} Point;

甚至可以省略結構體名稱:

typedef struct {
    float x;
    float y;
} Point;

 

三、typedef與指向結構體的指針

typedef可以給指針、結構體起別名,當然也可以給指向結構體的指針起別名

 1 #include <stdio.h>
 2 
 3 // 定義一個結構體並起別名
 4 typedef struct {
 5     float x;
 6     float y;
 7 } Point;
 8 
 9 // 起別名
10 typedef Point *PP;
11 
12 int main(int argc, const char * argv[]) {
13     // 定義結構體變量
14     Point point = {10, 20};
15     
16     // 定義指針變量
17     PP p = &point;
18     
19     // 利用指針變量訪問結構體成員
20     printf("x=%f,y=%f", p->x, p->y);
21     return 0;
22 }

在第4行定義了一個結構體,順便起了個別名叫Point,第10行為指向結構體的指針定義了別名PP。然后在main函數中使用這2個別名。

輸出結果:

 

四、typedef與枚舉類型

使用typedef給枚舉類型起別名也可以使代碼簡潔。

 1 // 定義枚舉類型
 2 enum Season {spring, summer, autumn, winter};
 3 // 給枚舉類型起別名
 4 typedef enum Season Season;
 5 
 6 int main(int argc, const char * argv[]) {
 7     // 定義枚舉變量
 8     Season s = spring;
 9     
10     return 0;
11 }

在第2行定義了枚舉類型,在第4行起了別名為Season,然后在第8行直接使用別名定義枚舉變量,不用再帶上enum關鍵字了。

第1行~第4行代碼可以簡化為:

// 定義枚舉類型,並且起別名
typedef enum Season {spring, summer, autumn, winter} Season

 甚至可以省略枚舉名稱,簡化為:

typedef enum {spring, summer, autumn, winter} Season;

 

五、typedef與指向函數的指針

1.先來回顧下函數指針的知識

 1 #include <stdio.h>
 2 
 3 // 定義一個sum函數,計算a跟b的和
 4 int sum(int a, int b) {
 5     int c = a + b;
 6     printf("%d + %d = %d", a, b, c);
 7     return c;
 8 }
 9 
10 int main(int argc, const char * argv[]) {
11     // 定義一個指向sum函數的指針變量p
12     int (*p)(int, int) = sum;
13     
14     // 利用指針變量p調用sum函數
15     (*p)(4, 5);
16     
17     return 0;
18 }

* 在第4行定義了一個sum函數,第12行定義了一個指向sum函數的指針變量p,可以發現,這個指針變量p的定義比一般的指針變量看來復雜多了,不利於理解。

* 第15行調用了p指向的sum函數,輸出結果:

 

2.為了簡化代碼和方便理解,我們可以使用typedef給指向函數的指針類型起別名

 1 #include <stdio.h>
 2 
 3 // 定義一個sum函數,計算a跟b的和
 4 int sum(int a, int b) {
 5     int c = a + b;
 6     printf("%d + %d = %d", a, b, c);
 7     return c;
 8 }
 9 
10 typedef int (*MySum)(int, int);
11 
12 int main(int argc, const char * argv[]) {
13     // 定義一個指向sum函數的指針變量p
14     MySum p = sum;
15     
16     // 利用指針變量p調用sum函數
17     (*p)(4, 5);
18     
19     return 0;
20 }

* 看第10行,意思是:給指向函數的指針類型,起了個別名叫MySum,被指向的函數接收2個int類型的參數,返回值為int類型。

* 在第14行直接用別名MySum定義一個指向sum函數的指針變量p,這樣看起來簡單舒服多了。第17行的函數調用是一樣的。

 

六、typedef與#define

1.先來看看下面的兩段代碼有什么區別(注意每一段的第1行代碼)

* 第1段

1 typedef char *String;
2 
3 int main(int argc, const char * argv[]) {
4     String str = "This is a string!";
5     return 0;
6 }

* 第2段

1 #define String char *
2 
3 int main(int argc, const char * argv[]) {
4     String str = "This is a string!";
5     return 0;
6 }

上面的兩段代碼只是第1行代碼不一樣,運行的效果都是一樣的:定義了一個字符串"This is a string!"

但它們的實現方式是不一樣的:

  • 第1段代碼是用typedefchar *定義別名為String
  • 第2段代碼是用char *代替代碼中的宏名String

只看上面兩段代碼,似乎看不太出typedef#define的區別。

 

2.再來看一段代碼

 1 typedef char *String1;
 2 
 3 #define String2 char *
 4 
 5 int main(int argc, const char * argv[]) {
 6     String1 str1, str2;
 7     
 8  String2 str3, str4;
 9     return 0;
10 }

第1行給char *起了個別名String1,第2行定義了宏String2。然后在第6、第8行定義了4個變量。

重點來了,注意:在這種情況下,只有str1、str2、str3才是指向char類型的指針變量,str4只是個char類型的變量

 

下面簡單分析一下原因:

* 如果連續聲明兩個int類型的變量,我們可以這樣寫:

int a, b;

上面的代碼相當於:

int a;
int b;

* 以此類推

1 typedef char *String1;
2     
3 String1 str1, str2;

經過typedef處理后,String1算是一種數據類型,所以第3行代碼相當於

1 String1 str1;
2 String1 str2;

由於String1就是char *,所以上面的兩行代碼等於

char *str1;
char *str2;

 

* 再看看宏定義的情況

1 #define String2 char *
2 
3 String2 str3, str4;

因為宏定義純粹是字符串替換,用char *代替String2,所以第3行代碼相當於

char * str3, str4;

其實也就相當於:

char * str3;
char str4;

可以看出,只有str4是基本數據類型,str1、str2、str3都是指針類型。

所以,以后給類型起別名,最好使用typedef,而不是使用#define


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM