1. 程式人生 > >C語言再學習 -- 關鍵字typedef

C語言再學習 -- 關鍵字typedef

一、typedef 介紹

typedef為C語言的關鍵字,作用是為一種資料型別定義一個新名字。比如人們常常使用 typedef 來編寫更美觀和可讀的程式碼。所謂美觀,意指 tepedef 能隱藏笨拙的語法構造以及平臺相關的資料型別,從而增強可移植性以及未來的可維護性。

這裡的資料型別包括內部資料型別(int,char等)和自定義的資料型別(struct等)。 在程式設計中使用typedef目的一般有兩個,一個是給變數一個易記且意義明確的新名字,另一個是簡化一些比較複雜的型別宣告。

typedef 使用方法如下:

typedef existing_type new_type_name;
注意:typedef 並不建立新的型別。它僅僅為現有型別新增一個同義字。

typedef的簡單應用:

typedef unsigned char BYTE;
BYTE b1, b2;

在這個型別定義之後,識別符號 BYTE 可作為型別 unsigned char 的縮寫。該定義的作用域取決於 typedef 語句所在的位置。如果定義是在一個函式內部,它的作用域是區域性的,限定在那個函式裡。如果定義是在函式外部,它將具有全域性作用域。

通常,這些定義使用大寫字母,以提醒使用者這個型別名稱實際上是一個符號縮寫。不過,您也可以使用小寫字母。

二、typedef 用法總結

1、typedef 與 define 區別

首先你要了解 typedef 和 define 的區別,巨集定義只是簡單的字串代換,是在預處理完成的,而typedef是在編譯時處理的,它不是作簡單的代換,而是對型別說明符重新命名。被命名的識別符號具有型別定義說明的功能。

請看下面的例子:

#define P1 int *

typedef (int *) P2

從形式上看這兩者相似,但在實際使用中卻不相同。

下面用P1、P2說明變數時就可以看出它們的區別:

P1 a, b;  在巨集代換後變成: int *a, b;  表示 a 是指向整型的指標變數,而 b 是整型變數。

P2 a, b;  表示a,b都是指向整型的指標變數。因為PIN2是一個型別說明符。

由這個例子可見,巨集定義雖然也可表示資料型別, 但畢竟是作字元代換。在使用時要分外小心,以避出錯。

總結,typedef和#define的不同之處:

1、與#define不同,typedef 給出的符號名稱僅限於對型別,而不是對值。

2、typedef 的解釋由編譯器,而不是是處理器執行。

3、雖然它的範圍有限,但在其受限範圍內,typedef 比 #define 更靈活。


2、常規變數型別定義

typedef 宣告可用來表示一個變數的含義。

例如:typedef unsigned char uchar
描述:uchar等價於unsigned char型別定義
           uchar c宣告等於unsigned char c宣告

3、陣列型別定義

例如: typedef int array[2];
描述: array等價於 int [2]定義;
            array a宣告等價於int a[2]宣告

擴充套件: typedef int array[M][N];
描述: array等價於 int [M][N]定義;
            array a宣告等價於int a[M][N]宣告

4、指標型別定義

例如: typedef int *pointer;
描述: pointer等價於 int *定義;
            pointer p宣告等價於int *p宣告

例如: typedef int *pointer[M];
描述: pointer等價於 int *[M]定義;
            pointer p宣告等價於int *p[M]宣告

5、函式地址說明
描述: C把函式名字當做函式的首地址來對待,我們可以使用最簡單的方法得到函式地址
例如: 函式:int func(void);
            unsigned long funcAddr=(unsigned long)func;
            funcAddr的值是func函式的首地址

6、函式宣告
例如: typedef int func(void);  
            func等價於 int (void)型別函式
描述1: func f宣告等價於 int f(void)宣告,用於檔案的函式宣告
描述2: func *pf宣告等價於 int (*pf)(void)宣告,用於函式指標的宣告,見下一條

7、函式指標
例如: typedef int (*func)(void)
描述: func等價於int (*)(void)型別
            func pf等價於int (*pf)(void)宣告,pf是一個函式指標變數

8、識別typedef的方法:
a).第一步。使用已知的型別定義替代 typdef 後面的名稱,直到只剩下一個名字不識別為正確
    如typedef u32   (*func)(u8);
    從上面的定義中找到 typedef __u32  u32; typedef __u8 u8
    繼續找到 typedef unsigned int __u32; typedef unsigned char __u8;
    替代位置名稱 typedef unsigned int  (*func)(void);
    現在只有func屬於未知
b).第二步.未知名字為定義型別,型別為取出名稱和 typedef 的所有部分,如上為
    func等價於unsigned unsigned  int  (*)(unsigned  char);
c).第三部.定義一個變數時,變數型別等價於把變數替代未知名字的位置所得到的型別
    func f等價於unsigned unsigned int  (*f)(unsigned char)

9、結構體定義

結構體的一般定義形式為:

標籤(tag)欄位允許為成員列表提供一個名字,這樣它就可以在後續的宣告中使用。標籤允許多個宣告使用同一個成員列表,並且建立同一種類型的結構。

  1. struct 標籤{    
  2.      型別名1 成員名1;  
  3.      型別名2 成員名2;  
  4.     ……  
  5.      型別名n 成員名n;     
  6.  }結構體變數;  
如果 標籤 存在,結構體變數 不存在,定義如下:
  1. struct Student{  
  2.     char name[20];//姓名
  3.     int age;//年齡
  4.     float height;//身高
  5. };  
  6. struct Student stu   //Student 為標籤  stu 為結構體變數
如果 結構體變數 存在, 標籤 可有可無,定義如下:
  1. struct Student{  //Student 可有可無
  2.     char name[20];//姓名
  3.     int age;//年齡
  4.     float height;//身高
  5. }stu;  
使用typedef起別名,標籤 可有可無,結構體變數 位置變為該 型別名
  1. typedefstruct Student{ //Student 可有可無
  2.     char name[20];//姓名
  3.     int age;//年齡
  4.     float height;//身高
  5. }Stu; //Stu 為型別名
  6. Stu stu; //Stu 為型別名,stu 為結構體變數
注意,字串初始化不能直接賦值,需要使用 strcpy 函式
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. typedefstruct
  4. {    
  5.     int n;    
  6.     float m;    
  7.     char name[20];    
  8. }Ptr;    
  9. int main (void)    
  10. {    
  11.     Ptr p;    
  12.     //Ptr p = {11, 12.9, "hello"};   
  13.     strcpy (p.name, "hello");  //注意字串不能直接賦值  
  14.     p.n = 11;    
  15.     p.m = 12.9;    
  16.     printf ("n = %d, name = %s, m = %g\n", p.n, p.name, p.m);    
  17.     return 0;    
  18. }    
  19. 輸出結果:    
  20. n = 11, name = hello, m = 12.9    

10、結構體指標

struct Node {
    int data;
    struct Node *nextptr;
};

使用 typede 上面的程式碼可以改寫為如下:
typedef struct Node pNode;
struct Node {
    int data;
    pNode *nextptr;
};

或者

typedef struct Node{
    int data;
    struct Node *nextptr;
}pNode;

三、typedef 用途

用途一:與#define的區別

typedef 行為有點像 #define 巨集,用其實際型別替代同義字。不同點是 typedef 在編譯時被解釋,

因此讓編譯器來應付超越前處理器能力的文字替換。

 用途二:減少錯誤

定義一種型別的別名,而不只是簡單的巨集替換。可以用作同時宣告指標型的多個物件。比如:

[cpp] view plain copy  print?
  1. char* pa, pb; // 這多數不符合我們的意圖,它只聲明瞭一個指向字元變數的指標,
  2. // 和一個字元變數;

以下則可行:

[cpp] view plain copy  print?
  1. typedefcharPCHAR;  
  2. PCHAR pa, pb;    

這種用法很有用,特別是char* pa, pb的定義,初學者往往認為是定義了兩個字元型指標,其實不是,而用typedef char* PCHAR就不會出現這樣的問題,減少了錯誤的發生。

用途三:    直觀簡潔

用在舊的C程式碼中,幫助struct。以前的程式碼中,宣告struct新物件時,必須要帶上struct,即形式為: struct 結構名物件名,如:

[cpp] view plain copy  print?
  1. struct tagPOINT1  
  2.  {  
  3.     int x;  
  4.     int y;   
  5. };  
  6. struct tagPOINT1 p1;  

而在C++中,則可以直接寫:結構名物件名,即:tagPOINT1 p1;

[cpp] view plain copy  print?
  1. typedefstruct tagPOINT  
  2. {  
  3.     int x;  
  4.     int y;  
  5. }POINT;  

POINT p1; // 這樣就比原來的方式少寫了一個struct,比較省事,尤其在大量使用的時候,或許,在C++中,typedef的這種用途二不是很大,但是理解了它,對掌握以前的舊程式碼還是有幫助的,畢竟我們在專案中有可能會遇到較早些年代遺留下來的程式碼。

用途四:平臺無關性

用typedef來定義與平臺無關的型別。

typedef 有另外一個重要的用途,那就是定義機器無關的型別,例如,你可以定義一個叫 REAL 的浮點型別,在目標機器上它可以獲得最高的精度:  [cpp] view plain copy  print?
  1. typedeflongdouble REAL;   
在不支援 long double 的機器上,該 typedef 看起來會是下面這樣:  [cpp] view plain copy  print?
  1. 相關推薦

    C語言學習 -- 關鍵字typedef

    一、typedef 介紹 typedef為C語言的關鍵字,作用是為一種資料型別定義一個新名字。比如人們常常使用 typedef 來編寫更美觀和可讀的程式碼。所謂美觀,意指 tepe

    C語言學習 -- 關鍵字struct(轉)

    結構體的一般定義形式為: 標籤(tag)欄位允許為成員列表提供一個名字,這樣它就可以在後續的宣告中使用。標籤允許多個宣告使用同一個成員列表,並且建立同一種類型的結構。 struct 標籤{ 型別名1 成員名1; 型別名2 成員名2; …… 型別名n 成員名n;    }結構體變數;

    C語言學習--關鍵字

    C語言一共有32個關鍵字,如下表所示: 關鍵字 說明 auto 宣告自動變數 short 宣告短整型變數或函式 int

    C語言學習 -- 關鍵字volatile

    上週確實事情挺多的,年會、公司聚餐,一到過年就有忙不完的事分心。還好C語言再學習總結的已經差不多了,年前也不展開別的了,接下來這十幾天、總結幾篇典型的面試題吧。 言歸正傳,接下來看看關鍵字 volatile。 一、volatile 介紹 Indicates that

    C語言學習 -- 儲存型別關鍵字

    C語言中有 5 個作為儲存類說明符的關鍵字,分別是 auto、register、static、extern 以及 typedef。關鍵字typedef 與記憶體儲存無關,由於語法原因被歸入此類。現在簡單瞭解一下這五個儲存類說明符的關鍵字:說明符 auto  表明一個變數具有自

    C語言學習-定義變數

    當我們在c語言裡建立一個變數的時候 int x = 5; int y = 6; 00C517B8 mov dword ptr [x],5 00C517BF mov dword ptr [y],6 實際上在彙編層面,

    C語言學習5-陣列與優化

    什麼是陣列?為什麼要用陣列? 通俗來講,在記憶體中一塊連續儲存資料的叫陣列,陣列的每個子元素的寬度都一樣,並且只能為通用的資料型別做單位(char,short,int等等) 讓我們先定義一個數組,然後賦值: char arr1[2] = { 0 }; arr1

    C語言學習7-結構體

    為什麼使用結構體? struct My { char name[20] = "如風斬嶽"; int age; char addr[50] ; int money; double Coordinates; //..... }; 當我們有這樣一種需求,

    C語言學習 -- 負數

    有符號數的表示方法是由硬體決定,而不是由C決定的。有三種表示方法: 1、二進位制原碼 0000 0001  表示 1 1000 0001  表示 -1 這個方法有個缺點是有兩個零: +0 和 -0。這會引起混淆,而且用兩個位

    C語言學習 -- 檔案

    檔案是什麼 一個檔案(file)通常就是磁碟上的一段命名的儲存區。C 將檔案看成是連續的位元組序列,其中每一個位元組都可以單獨地讀取。 二進位制和文字模式 1、在windows系統中,文字模式

    C語言學習 -- ASCII碼錶(轉)

    ASCII碼錶第一部分:ASCII非列印控制字元表ASCII表上的數字0–31分配給了控制字元,用於控制像印表機等一些外圍裝置。例如,12代表換頁/新頁功能。此命令指示印表機跳到下一頁的開頭。(參詳ASCII碼錶中0-31)第二部分:ASCII列印字元數字 32–126 分配給了能在鍵盤上找到的字元,當您檢視

    【 分類 】- C語言學習

    專欄達人 授予成功建立個人部落格專欄

    C語言學習 -- 詳解C++/C 面試題 1

    對這篇文章記憶猶新,因為之前找工作面試的時候,遇到過一家公司就是用的這套面試題。現在就結合考查的知識點和我總結完 C 語言再學習後的深入理解,來詳細的講講我對這篇文章的總結。 一、請填寫BOOL ,

    C語言學習 -- 論記憶體管理

    但現在看來,缺少示例。從新再寫一篇文章,著重介紹常見記憶體錯誤、跨函式使用儲存區。開始吧,再論記憶體管理!!發生記憶體錯誤是件非常麻煩的事情。編譯器不能自動發現這些錯誤,通常是在程式執行時才能捕捉到。而這些錯誤大多沒有明顯的症狀時隱時現增加了改錯的難度。一、常見的記憶體錯誤及

    C語言學習 -- 記憶體管理

    malloc ( )函式: malloc ( ) 向系統申請分配指定size個位元組的記憶體空間。返回型別是 void* 型別。void* 表示未確定型別的指標。C,C++規定,void* 型別可

    C語言學習 -- 時間函式

    gmtime函式:可以把time函式得到的結果按照格林尼治時間轉換成一個結構體localtime函式:可以把time函式得到的結果按照當前時區轉換成一個結構體asctime函式:可以把一個記錄時間的結構體轉換成字串,一般與上兩個函式合用的格林時間,與北京時間換算,/* 時間函式演示 */ #

    C語言學習 -- 論陣列和指標

    之前有總結指標陣列,但是現在看來總結的太簡單了。好多重要的知識點都是一帶而過的。本想在後面新增後來想想算了,還是再寫一篇文章來詳細介紹陣列和指標這對冤家吧。一開始覺得C語言再學習專欄都寫了五十篇了,現在

    C語言學習 -- NUL和NULL的區別

    NUL 是ASCII 字符集中 '\0' 字元的名字,它的位元組模式為全 0。NULL 指一個其值為 0 的指標。它們都是整型值,其值也相同,所以它們可以互換使用。然而,你還是應該使用適當的常量,因為

    C語言學習 -- 段錯誤(核心已轉儲)

    一、什麼是段錯誤?一旦一個程式發生了越界訪問,cpu 就會產生相應的保護,於是 segmentation fault 就出現了,通過上面的解釋,段錯誤應該就是訪問了不可訪問的記憶體,這個記憶體區要麼是不存在的,要麼是受到系統保護的,還有可能是缺少檔案或者檔案損壞。二、段錯誤產

    C語言學習 -- 詳解C++/C 面試題 2

    (經典)C語言測試:想成為嵌入式程式設計師應知道的0x10個基本問題。1、用預處理指令#define 宣告一個常數,用以表明1年中有多少秒(忽略閏年問題) #define SENCONDS_PER_YE