一、與typedef相關的預備知識
1.1 C語言的兩種類型
- 內建類型
ADT
(也叫原生類型、基礎數據類型):編譯器自帶的類型,如int/double
等 - 自定義類型
UDT
:不是編譯器自帶的類型,是程序員自己定義的,如結構體類型、數組類型、函數指針類型等
1.2 typedef加工的是類型而不是變量
- 類型就是一個數據模板,變量是一個實在的數據
- 類型是不佔內存的,變量是佔內存的
- 在面向對象的語言中,類型就是類
class
,變量就是對象 typedef
不新建類型,只是對現有的類型進行重命名
二、typedef
與#define宏
的區別
2.1 原理不同
typedef
是關鍵字,它在自己的作用域內給一個已經存在的類型一個別名,在編譯時處理,有類型檢查功能。#define
是C語言
中的宏定義,是預處理指令,在預處理時進行簡單而機械的字符串替換,不作正確性檢查
2.2 功能不同
typedef
用來定義類型的別名,方便使用#define
除爲類型重命名外,還可以定義常量、變量、簡化複雜運算
2.3 對指針的操縱範圍不同
2.3.1 測試代碼
typedef char* pChar1;
#define pChar2 char*
int main(void)
{
pChar1 c1, c2;
pChar2 c3, c4;
char* p;
p = c1;
p = c2;
p = c3;
p = c4;
return 0;
}
2.3.2 測試結果
我們可以看到,在p = c4
處有警告:
warning: assignment makes pointer from integer without a cast
即:警告:在沒有強制轉換的情況下將整數值賦給指針
也就是說c4
其實只是一個char
型變量而c2
不是!!!
三、typedef
與結構體
3.1 結構體在使用時的常規步驟:
- 先定義結構體的類型
- 結構體的類型去定義變量
- 使用結構體成員
/*定義結構體類型,不佔內存*/
struct student
{
char name[20];
int age;
char sex[10];
};
int main(void)
{
struct student s1;
//struct student是類型,不佔內存;s1是變量,佔內存
s1.age = 20;//結構體成員的使用
}
3.2 typedef簡化變量定義
C語言
語法規定,結構體使用時必須是struct 結構體類型名 結構體變量名
的形式,如果需要大量使用結構體,這樣略爲麻煩,可以使用typedef
來簡化,如:
typedef struct student
{
char name[20];
int age;
char sex[10];
}student_t;
這時就一下定義了兩個類型名:struct student
和student_t
;
也就是說struct student s1;
就可以簡化定義爲student_t s1
在很多情況下,會直接簡化爲:
typedef struct student
{
char name[20];
int age;
char sex[10];
}student;
同時使用兩個student
在C語言
中是允許的,這也同時定義了兩個類型名:
struct student
和student
在結構體的定義時,也可以同時定義兩個類型,如下所示:
typedef struct student
{
char name[20];
int age;
char sex[10];
}student, *pStudent;
在這裏面,第一個是結構體類型,有兩個類型名:struct student
和student
第二個是結構體指針類型:有兩個類型名:struct student *
和pStudent
測試代碼:
int main(void)
{
student s1;
s1.age = 20;
pStudent p1 = &s1;
printf("student s1 age = %d\n", p1 -> age);
return 0;
}
測試結果:
四、typedef
與const
4.1 代碼段1
typedef int* PINT;
const PINT p;
相當於是 int *const p;
也就是說p
是不可變的,p
指向的變量是可變的
4.2 代碼段2
typedef int* PINT;
PINT const p;
也相當於是 int *const p;
4.3 如果想得到const int *p;
typedef const int *CPINT;
CPINT p;
4.4 測試代碼:
#include <stdio.h>
typedef int *PINT;
typedef const int *CPINT;
int main(void)
{
int arr[2] = {1, 2};
/*指向的初始地址*/
const PINT p0 = &arr[0];
PINT const p1 = &arr[0];
CPINT p2 = &arr[0];
/*嘗試改變指向的地址*/
p0 = &arr[1];
p1 = &arr[1];
p2 = &arr[1];
/*嘗試改變指向的變量*/
*p0 = arr[1];
*p1 = arr[1];
*p2 = arr[1];
return 0;
}
4.5 編譯結果:
我們可以看到編譯時報了三個error
:
4.5typedef.c:52:8: error: assignment of read-only variable ‘p0’
p0 = &arr[1];
^
4.5typedef.c:53:8: error: assignment of read-only variable ‘p1’
p1 = &arr[1];
^
4.5typedef.c:58:9: error: assignment of read-only location ‘*p2’
*p2 = arr[1];
^
即p0、p1、*p2
都是隻讀的,也就應證了前面所說的三個代碼段。
五、typedef
與函數指針
如c標準庫
中的strcpy
函數:
char *strcpy(char *dest, const char *src);
定義三個指向該函數的函數指針:
char * (*p1) (char *, const char *);
char * (*p2) (char *, const char *);
char * (*p3) (char *, const char *);
使用typedef來簡化:
typedef char * (*pFunc) (char *, const char *);
pFunc p1, p2, p3;
其中,typedef
重命名了一個類型,這個類型新名字叫pFunc
;
類型是:char * (*) (char *, const char *);
六、使用typedef
的意義
- 簡化類型的描述
- 創造平臺無關類型
在很多編程體系下,人們傾向於不使用int、double
等這些與平臺相關的平臺內建類型(int
在32位
機上是32
位的,64位
機上是64位
的)。爲了解決這個問題,很多程序使用自定義的中間類型來緩衝。比如:
/*自定義中間類型來做緩衝*/
typedef int sizet_32;
typedef int lent_64;
typedef volatile unsigned int vn32;
/*使用自定義類型來定義變量*/
sizet_32 a;
lent_64 b;
vn32 c;