首頁 > 軟體

C++ typedef常見用法詳解

2023-03-09 06:05:02

typedef的4種常見用法:

  • 給已定義的變數型別起個別名
  • 定義函數指標型別
  • 定義陣列指標型別
  • 為複雜的宣告定義一個新的簡單的別名

總結一句話:“加不加typedef,型別是一樣的",這句話可以這樣理解:

沒加typedef之前如果是個陣列,那麼加typedef之後就是陣列型別;

沒加typedef之前如果是個函數指標,那麼加typedef之後就是函數指標型別;

沒加typedef之前如果是個指標陣列,那麼加typedef之後就是指標陣列型別。

typedef char TA[5];//定義陣列型別
typedef char *TB[5];//定義指標陣列型別,TB定義的變數為含5個char*指標元素的陣列(指標陣列型別)
typedef char *(TC[5]);//指標陣列型別,因為[]的結合優先順序最高,所以加不加()沒啥區別,TC等價於TB
typedef char (*TD)[5];//陣列指標型別,TD指向一個5容量的char陣列
後文簡單介紹下指標陣列和陣列指標

typedef的4種用法詳解

1、給已定義的變數型別起個別名

(1)typedef unsigned char uin8_t; //uint8_t就是unsigned char的別名,這是最基礎的用法;

(2)結構體用法——作用是給struct __person起了個別名person_t,這種這種用法也很基礎;

struct __person
{
    char    name[20];
    uint8_t age;
    uint8_t height;
}
typedef __person person_t;
 
//以上兩段程式碼也可合併為一段,如下:
typedef struct __person
{
    char    name[20];
    uint8_t age;
    uint8_t height;
}person_t;

2、定義函數指標型別

首先來看一下如何定義函數指標變數,然後再看如何定義函數指標型別。

(1)定義函數指標變數

定義了一個函數指標變數pFunc,它可以指向這樣的函數:返回值為int,形參為char*、int:

int (*pFunc)(char *frame, int len);

定義了5個函數指標變數:pFunc[0]、pFunc[1]···,它們都可以指向這樣的函數:返回值為int*,形參為int:

int *(*pFunc[5])(int len);

(2)定義函數指標型別

定義函數指標型別,必須使用typedef,方法就是,在“定義函數指標變數”前加上typedef。

typedef int (*pFunc_t)(char *frame, int len);//定義了一個型別pFunc_t

舉例:

typedef  int (*pFunc_t)(char *frame, int len);//定義了一個型別pFunc_t
int read_voltage(char *data, int len)
{
    int voltage = 0;
    ···//其他功能程式碼
    return voltage;
}
int main(void)
{
    pFunc_t   pHandler = read_voltage;//使用型別pFunc_t來定義函數指標變數
    ···//其他功能程式碼
}

3、定義陣列指標型別

這個問題還是分兩步,先看如何定義陣列指標變數,再看如何定義陣列指標型別。

(1)定義陣列指標變數

  • int(*pArr)[5];//定義了一個陣列指標變數pArr,pArr可以指向一個int [5]的一維陣列

  • char(*pArr)[4][5];///定義了一個陣列指標變數pArr,pArr可以指向一個char[4][5]的二維陣列

char(*pArr)[4][5];///定義了一個陣列指標變數pArr,pArr可以指向一個char[4][5]的二維陣列

int(*pArr)[5];//pArr是一個指向含5個int元素的一維陣列的指標變數
int a[5] = {1,2,3,4,5};
int b[6] = {1,2,3,4,5,6};
pArr = &a;//完全合法,無警告
pArr = a;//發生編譯警告,賦值時型別不匹配:a的型別為int(*),而pArr的型別為int(*)[5]
pArr = &a[0];//發生編譯警告,賦值時型別不匹配:a的型別為int(*),而pArr的型別為int(*)[5]
pArr = &b;//發生編譯警告,賦值時型別不匹配:&b的型別為int(*)[6],而pArr的型別為int(*)[5]
pArr = (int(*)[5])&b;//型別強制轉換為int(*)[5],完全合法,無警告

上面這個例子中,使用型別轉換時,程式碼的樣式略顯複雜,試想,我們如果強轉為一個結構體陣列的指標,那這個強轉的括號裡的內容得多長!這就直接影響了程式碼的可讀性,因此,強轉後的型別應該定義出來。

(2)定義陣列指標型別

如同上面定義函數指標型別的方法,直接在前面加typedef即可,例如:

typedef int (*pArr_t)[5];//定義了一個指標型別pArr_t,該型別的指標可以指向含5個int元素的陣列
typedef int(*pArr_t)[5];//定義一個指標型別,該型別的指標可以指向含5個int元素的一維陣列
 
int main(void)
{
    int a[5] = {1,2,3,4,5};
    int b[6] = {1,2,3,4,5,6};
    pArr_t pA;//定義陣列指標變數pA
    pA= &a;//完全合法,無警告    
    pA= (pArr_t)&b;//型別強制轉換為pArr_t,完全合法,無警告
}

(3)定義陣列型別

如果我們想宣告一個含5個int元素的一維陣列,一般會這麼寫:int a[5];

如果我們想宣告多個含5個int元素的一維陣列,一般會這麼寫:int a1[5], a2[5], a3[5]···,或者 a[N][5]

可見,對於定義多個一維陣列,寫起來略顯複雜,這時,我們就應該把陣列定義為一個型別,例如:

typedef int arr_t[5];//定義了一個陣列型別arr_t,該型別的變數是個陣列。
typedef int arr_t[5];
int main(void)
{
    arr_t d;        //d是個陣列,這一行等價於:  int d[5];
    arr_t b1, b2, b3;//b1, b2, b3都是陣列
    
    d[0] = 1;
    d[1] = 2;
    d[4] = 134;
    d[5] = 253;//編譯警告:下標越界
}

4、為複雜的宣告定義一個新的簡單的別名

為複雜的宣告定義一個新的簡單的別名。方法是:在原來的宣告裡逐步用別名替換一部分複雜宣告,如此迴圈,把帶變數名的部分留到最後替換,得到的就是原宣告的最簡化版。舉例:

int *(*a[5])(int, char*);//原宣告
 
typedef int *(*pFun)(int, char*); //變數名為a,直接用一個新別名pFun替換a就可以了
pFun a[5];//原宣告的最簡化版
void (*b[10]) (void (*)());//原宣告
 
typedef void (*pFunParam)();//變數名為b,先替換右邊部分括號裡的,pFunParam為別名一
typedef void (*pFunx)(pFunParam);//再替換左邊的變數b,pFunx為別名二
 
pFunx b[10];//原宣告的最簡化版

兩大陷阱

陷阱一:記住,typedef是定義了一種型別的新別名,不同於宏,它不是簡單的字串替換。

陷阱二:typedef在語法上是一個儲存類的關鍵字(如auto、extern、mutable、static、register等一樣),雖然它並不真正影響物件的儲存特性。

typedef 與 #define的區別

案例一:

通常講,typedef要比#define要好,特別是在有指標的場合。請看例子:

typedef char *pStr1;  
#define pStr2 char *;  
pStr1 s1, s2;  
pStr2 s3, s4; 

在上述的變數定義中,s1、s2、s3都被定義為char *,而s4則定義成了char,不是我們所預期的指標變數,根本原因就在於#define只是簡單的字串替換而typedef則是為一個型別起新名字。

案例二:

下面的程式碼中編譯器會報一個錯誤,你知道是哪個語句錯了嗎?

typedef char * pStr;  
char str[4] = "abc";  
const char *p1 = str;  
const pStr p2 = str;  
p1++;  
p2++; 

是p2++出錯了。這個問題再一次提醒我們:typedef和#define不同,它不是簡單的文字替換。上述程式碼中const pStr p2並不等於const char * p2。const pStr p2和const long x本質上沒有區別,都是對變數進行唯讀限制,只不過此處變數p2的資料型別是我們自己定義的而不是系統固有型別而已。因此,const pStr p2的含義是:限定資料型別為pStr 的變數p2為唯讀,因此p2++錯誤。

對於指標陣列和陣列指標的概念,相信很多人經常會感到迷惑,見到二者一時不能分辨究竟對應哪一個才是對的。接下來我們來分析一下二者區別。

我們來看一下這個範例程式碼:

int *ptr1[10];
int (*ptr2)[10];

對於上述程式碼語句,你是否能分清哪一句程式碼宣告的是指標陣列,而哪一句程式碼宣告的又是陣列指標呢?

答案是第一行程式碼宣告的ptr1是一個指標陣列,陣列名為 ptr1,而“int*”修飾的是陣列的內容,該陣列包含 5 個 指向 int 型別 資料的指標。第二行程式碼宣告的ptr2則是一個 陣列的指標 ,指標變數名為 ptr2,而 int 修飾的是陣列的內容,即陣列的每個元素。即ptr2 是一個指標,它指向一個包含 5 個 int 型別資料的陣列。

這裡其實可以首先看*能否與前面的型別結合,能的話,內容就是結合後的內容。

到此這篇關於C++ typedef用法詳解的文章就介紹到這了,更多相關C++ typedef用法內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com