零基礎學C語言——自定義類型typedef

這是一個C語言系列文章,如果是初學者的話,建議先行閱讀之前的文章。筆者也會按照章節順序發佈。

之前的文章中已經介紹過了 、 ,本文介紹在C語言中如何自定義類型,或者也可以說是如何給現有類型定義別名。

自定義類型主要通過typedef關鍵字來定義,根據不同的寫法我將自定義分為兩類:定義變量類型定義函數指針

定義變量類型

在定義變量類型是,typedef的一般形式為:

<code>typedef 原始類型名 自定義類型名;/<code>

可以看到,對於變量類型的自定義,更多的相當於是對變量類型的一個重命名。下面給出一些例子:

<code>typedef int int32_t;
typedef unsigned int uint32_t;
typedef float r32_t;
typedef double r64_t;/<code>

這裡將int、unsigned int、float、double四個類型分別又定義了一個類型別名。這並非是從此就不能用這四個類型關鍵字定義變量了,而是額外增加了4個類型等價於之前的4個類型。

假如,我們有如下代碼:

<code>#include <stdio.h>

int main(void)
{
int i = 10;
float f = 3.14;
printf("%d %f\\n", i, f);
return 0;
}/<stdio.h>/<code>

那麼利用新定義的4個類型,我們可以將其改為:

<code>#include <stdio.h>

typedef int int32_t;
typedef unsigned int uint32_t;
typedef float r32_t;
typedef double r64_t;

int main(void)
{
int32_t i = 10;
r32_t f = 3.14;
printf("%d %f\\n", i, f);
return 0;
}/<stdio.h>/<code>

可以看到main的返回值依舊是int。這段代碼的含義與前一段代碼的含義完全一致。

下面來看看結構體的類型自定義

<code>struct person {
char name[64];
unsigned long age:63;
unsigned long sex:1;
};/<code>

這裡有幾種寫法給struct person定義類型別名:

<code>//方法一,形式與變量類型自定義完全一致
typedef struct person person_t;

//方法二,在定義結構體的同時進行類型別名的定義,
//方法是在struct關鍵字前加typedef,並在}後跟類型別名,然後才是分號結束
typedef struct person {
char name[64];
unsigned long age:63;
unsigned long sex:1;
} person_t;

//方法三,有時候我們只需要自定義的類型別名,而不需要結構體名,所以結構體名可以省略不寫
typedef struct {
char name[64];
unsigned long age:63;
unsigned long sex:1;
} person_t;/<code>

共同體與結構體類似:

<code>union identity {
struct person employee;
struct person child;
struct person parent;
};

//方法一
typedef union identity identity_t;
//方法二
typedef union identity {
struct person employee;
struct person child;

struct person parent;
} identity_t;
//方法三
typedef union {
struct person employee;
struct person child;
struct person parent;
} identity_t;/<code>

枚舉類型同理:

<code>enum week {
Monday,
Tuesday = 0,
Wednesday,
Thursday,
Friday = Wednesday+99,
Saturday,
Sunday
};

//方法一
typedef enum week week_t;
//方法二
typedef enum week {
Monday,
Tuesday = 0,
Wednesday,
Thursday,
Friday = Wednesday+99,
Saturday,
Sunday
} week_t;
//方法三
typedef enum {
Monday,
Tuesday = 0,
Wednesday,
Thursday,
Friday = Wednesday+99,
Saturday,
Sunday
} week_t;/<code>

定義函數指針

C語言中,函數除卻函數名不同以外,函數的返回值類型、參數個數、參數類型都有可能不同。但是,也存在一類函數,它們除了名字不同外,其他全部相同。這樣的函數,它們同屬一個類型。換言之,函數是有類型的,它們的類型是由返回值類型、參數個數、參數類型共同定義的

函數類型的一般形式如下:

<code>typedef 返回值類型 (*函數類型名) (參數列表);/<code>

其中參數列表處僅給出參數類型即可。

這裡定義的是一個函數指針,我們在 一文中提到過,每一個函數都有其對應的內存地址,因為函數代碼也是要放入內存中運行的。因此,一個能存儲函數位置的變量,是一個指針變量,這種指針變量稱作函數指針

我們看幾個例子,這裡我們沿用上一小節中結構體定義和其類型別名。假設我們有如下函數定義:

<code>int add(int num1, int num2)
{
return num1+num2;
}


person_t *modify(person_t *someone)
{
someone->age = 28;
return someone;
}/<code>

那麼這些函數對應的函數指針定義就是:

<code>typedef int (*ptr_add) (int, int);
typedef person_t *(*ptr_modify)(person_t *);/<code>

有了指針,我們來看下如何使用這些指針:

<code>int main(void)
{
ptr_add my_add = add; //定義了一個ptr_add類型的函數指針變量my_add
ptr_modify my_modify = modify; //定義了一個ptr_modify類型的函數指針變量my_modify
printf("add result: %d\\n", my_add(1, 2));//函數指針的使用與正常函數調用是一樣的,就相當於給函數起了一個別名
person_t John = {"John", 18, 0};
person_t *ret = my_modify(&John);
printf("age: %lu\\n", ret->age);
return 0;
}/<code>

綜合用例

<code>#include <stdio.h>

typedef struct person person_t;
typedef void (*eat_t)(person_t *);

struct person {
unsigned long id:54;
unsigned long age:8;
unsigned long sex:1;
unsigned long hungry:1;
eat_t eat;
};

void reset_hungry(person_t *someone)
{
someone->hungry = 0;
}

int main(void)
{
int i;
person_t group[3];
for (i = 0; i < sizeof(group)/sizeof(person_t); ++i) {
group[i].id = i;
group[i].age = 18;
group[i].sex = 0;
group[i].hungry = 1;
group[i].eat = reset_hungry;
}

for (i = 0; i < sizeof(group)/sizeof(person_t); ++i) {
group[i].eat(&group[i]);
}

for (i = 0; i < sizeof(group)/sizeof(person_t); ++i) {
printf("id:%lu hungry:%lu\\n", group[i].id, group[i].hungry);
}
return 0;
}/<stdio.h>/<code>

例子很簡單,定義了一個person_t類型,這是個結構體,模擬了人的id、年齡、性別、飢餓與否。

由於每個人的進食都是一樣的,因此定義了一個進食類型的函數指針放在person_t中,以便在需要進食時調用指針指向的函數。

main函數中第一輪for循環用來初始化person_t數組,所有person都是飢餓的。第二輪for循環用來調用eat函數指針變量指向進食函數來進食。第三輪for循環輸出每個person當前的飢餓狀態。

輸出結果:

<code>


喜歡的小夥伴可以關注碼哥,也可以給碼哥留言評論,如有建議或者意見也歡迎私信碼哥,我會第一時間回覆。


分享到:


相關文章: