iT邦幫忙

2026 iThome 鐵人賽

DAY 3
0
自我挑戰組

韌體工程師的不只 0x10 個問題系列 第 3

Day 3 - 為何用 typedef 比 #define 定義新資料型別更好?

  • 分享至 

  • xImage
  •  

如果要定義一個「指向結構 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 * 這個指向結構的指標取別名,那兩者是否有差別呢?

#definetypedef 的比較

在分別用 #definetypedef 定義完「指向結構 struct s 指標」的寫法後,如果要同時宣告兩個指標變數,寫法會分別變成:

dPS p1, p2;
tPS p3, p4;

p1p2p3p4 各自是什麼?

透過以下程式碼觀察可略知一二:

#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

p1p3p4 都佔據 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 沒有 *,因此只是一般結構變數

如果要讓 p1p2 都變成指標,那宣告時便要很拗口地寫成:

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 *

不論 p3p4,都是完整的 struct s *

參考資料

  1. 韌體工程師的0x10個問題

上一篇
Day 2-C 語言的預處理器
下一篇
Day 4-內嵌函數
系列文
韌體工程師的不只 0x10 個問題5
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言