如果要定義一個「指向結構 struct s 的指標」,可以怎麼寫?
Day 2 的文章有講過用巨集的寫法:
#define dPS struct s *
這行程式碼的意思為:
#define:預處理器指令,表示要建立一個巨集。dPS:巨集名稱。struct s:結構型態,標籤名稱為 s。*:指向 struct s 的指標。還有另外一種用 typedef 的寫法:
typedef struct s * tPS;
這行程式碼的意思為:
typedef:表示要為現有指向結構的指標 struct s * 定義一個別名 tPS。struct s:結構型態,標籤名稱為 s。*:指向 struct s 的指標。tPS:指向 struct s 的指標之別名。既然都能為 struct s * 這個指向結構的指標取別名,那兩者是否有差別呢?
#define 跟 typedef 的比較在分別用 #define 跟 typedef 定義完「指向結構 struct s 指標」的寫法後,如果要同時宣告兩個指標變數,寫法會分別變成:
dPS p1, p2;
tPS p3, p4;
那 p1、p2、p3、p4 各自是什麼?
透過以下程式碼觀察可略知一二:
#include <stdio.h>
struct s {
char data[100]; // 假設結構 s 大小為 100 個位元組
};
// 使用 #define
#define dPS struct s *
// 使用 typedef
typedef struct s * tPS;
int main() {
// ---- 測試 #define ----
dPS p1, p2;
// ---- 測試 typedef ----
tPS p3, p4;
// 觀察 p1、p2、p3、p4 的位元組大小
printf("=== #define ===\n");
printf("p1 is %zu bytes\n", sizeof(p1));
printf("p2 is %zu bytes\n", sizeof(p2));
printf("=== typedef ===\n");
printf("p3 is %zu bytes\n", sizeof(p3));
printf("p4 is %zu bytes\n", sizeof(p4));
return 0;
}
結果如下:
=== #define ===
p1 is 8 bytes
p2 is 100 bytes
=== typedef ===
p3 is 8 bytes
p4 is 8 bytes
p1、p3 跟 p4 都佔據 8 個位元組,也就是 64 位元電腦中指標的大小,但唯獨 p2 佔據 100 個位元組,等同是一個完整的 struct s,為什麼?
#define 的意義#define 的意思是還沒到編譯階段,就由預處理器直接展開、做文字代換,也就是說,之後只要看到 dPS 就用 struct s * 替代,所以:
dPS p1, p2;
替代成 struct s * p1, p2;
這樣等同於:
struct s *p1; // * 只搭配到 p1,表示 p1 是一個指標
struct s p2; // p2 沒有 *,因此只是一般結構變數
如果要讓 p1 跟 p2 都變成指標,那宣告時便要很拗口地寫成:
dPS p1, * p2;
這樣才等同於:
struct s *p1; // 這裡的 * 由 dPS 展開成 struct s * 而來
struct s *p2; // 這裡的 * 是手動加上去的
雖然可以達成預期中的效果,但在 p2 手動補 *,寫起來是不是很彆扭?
typedef 的意義與好處如果寫成 typedef struct s * tPS;,那它的意思是:
struct s *:這個結構放進一個「盒子」。tPS:這個「盒子」的名稱就是 tPS。也就是說,之後用 tPS 做出來的每個變數,都是一個完整的 struct s *,因此:
tPS p3, p4;
相當於:
struct s *p3; // 由 tPS 展開成完整的 struct s *
struct s *p4; // 由 tPS 展開成完整的 struct s *
不論 p3 或 p4,都是完整的 struct s *。