typedef struct 《轉載的》

  1. 轉載 http://www.iteye.com/topic/143629

  2. 由於對typedef理解不夠,因此從網上摘錄了一些資料,整理如下:   
  3.   
  4. C/C++中typedef struct和struct的用法   
  5.   
  6. struct  _x1 { ...}x1; 和 typedef  struct  _x2{ ...} x2; 有什麼不同?   
  7.   
  8.     
  9. 其實, 前者是定義了類_x1和_x1的對象實例x1,  後者是定義了類_x2和_x2的類別名x2 ,   
  10.   
  11. 所以它們在使用過程中是有取別的.請看實例1.   
  12.   
  13.  [知識點]   
  14.   
  15. 結構也是一種數據類型, 可以使用結構變量, 因此,  象其它 類型的變量一樣, 在使用結構變量時要先對其定義。   
  16.   
  17.     定義結構變量的一般格式爲:   
  18.   
  19.      struct 結構名   
  20.   
  21.      {   
  22.   
  23.           類型  變量名;   
  24.   
  25.           類型  變量名;   
  26.   
  27.           ...   
  28.   
  29.      } 結構變量;   
  30.   
  31.     結構名是結構的標識符不是變量名。   
  32.   
  33.     
  34.   
  35. 另一種常用格式爲:     
  36.   
  37.     
  38.   
  39.  typedef struct 結構名   
  40.   
  41.      {   
  42.   
  43.           類型  變量名;   
  44.   
  45.           類型  變量名;   
  46.   
  47.           ...   
  48.   
  49.      } 結構別名;   
  50.   
  51.     
  52.   
  53.     
  54.   
  55. 另外注意:  在C中,struct不能包含函數。在C++中,對struct進行了擴展,可以包含函數。   
  56.   
  57.     
  58.   
  59. ======================================================================   
  60.   
  61.     
  62.   
  63. 實例1:  struct.cpp   
  64.   
  65.     
  66.   
  67. #include <iostream>  
  68.   
  69. using namespace std;   
  70.   
  71. typedef struct _point{   
  72.   
  73.           int x;   
  74.   
  75.           int y;   
  76.   
  77.           }point; //定義類,給類一個別名    
  78.   
  79.                     
  80.   
  81. struct _hello{   
  82.   
  83.        int x,y;          
  84.   
  85.       } hello; //同時定義類和對象   
  86.   
  87.           
  88.   
  89.             
  90.   
  91. int main()   
  92.   
  93. {             
  94.   
  95.     point pt1;         
  96.   
  97.     pt1.x = 2;   
  98.   
  99.     pt1.y = 5;   
  100.   
  101.     cout<< "ptpt1.x=" << pt1.x << "pt.y=" <<pt1.y <<endl;   
  102.   
  103.     
  104.   
  105.  //hello pt2;    
  106.   
  107.     //pt2.x = 8;   
  108.   
  109.     //pt2.y =10;   
  110.   
  111.     //cout<<"pt2pt2.x="<< pt2.x <<"pt2.y="<<pt2.y <<endl;   
  112.   
  113.     //上面的hello pt2;這一行編譯將不能通過. 爲什麼?   
  114.   
  115.     //因爲hello是被定義了的對象實例了.   
  116.   
  117.     //正確做法如下: 用hello.x和hello.y   
  118.   
  119.          
  120.   
  121.     hello.x = 8;   
  122.   
  123.     hello.y = 10;     
  124.   
  125.     cout<< "hellohello.x=" << hello.x << "hello.y=" <<hello.y <<endl;   
  126.   
  127.          
  128.   
  129.     return 0;                
  130.   
  131. }   
  132.   
  133.     
  134.   
  135.     
  136.   
  137. typedef struct與struct的區別   
  138.   
  139. 1. 基本解釋   
  140.   
  141. typedef爲C語言的關鍵字,作用是爲一種數據類型定義一個新名字。這裏的數據類型包括內部數據類型(int,char等)和自定義的數據類型(struct等)。   
  142.   
  143.     
  144.   
  145. 在編程中使用typedef目的一般有兩個,一個是給變量一個易記且意義明確的新名字,另一個是簡化一些比較複雜的類型聲明。   
  146.   
  147.     
  148.   
  149. 至於typedef有什麼微妙之處,請你接着看下面對幾個問題的具體闡述。   
  150.   
  151.     
  152.   
  153. 2. typedef & 結構的問題   
  154.   
  155.     
  156.   
  157. 當用下面的代碼定義一個結構時,編譯器報了一個錯誤,爲什麼呢?莫非C語言不允許在結構中包含指向它自己的指針嗎?請你先猜想一下,然後看下文說明:   
  158.   
  159.     
  160.   
  161. typedef struct tagNode   
  162.   
  163. {   
  164.   
  165.  char *pItem;   
  166.   
  167.  pNode pNext;   
  168.   
  169. } *pNode;    
  170.   
  171.     
  172.   
  173. 答案與分析:   
  174.   
  175.     
  176.   
  177. 1、typedef的最簡單使用   
  178.   
  179.     
  180.   
  181. typedef long byte_4;   
  182.   
  183.     
  184.   
  185.   給已知數據類型long起個新名字,叫byte_4。   
  186.   
  187.     
  188.   
  189. 2、 typedef與結構結合使用   
  190.   
  191.     
  192.   
  193. typedef struct tagMyStruct   
  194.   
  195. {   
  196.   
  197.  int iNum;   
  198.   
  199.  long lLength;   
  200.   
  201. } MyStruct;   
  202.   
  203.     
  204.   
  205. 這語句實際上完成兩個操作:   
  206.   
  207.     
  208.   
  209.   1) 定義一個新的結構類型   
  210.   
  211.     
  212.   
  213. struct tagMyStruct   
  214.   
  215. {   
  216.   
  217.  int iNum;   
  218.   
  219.  long lLength;   
  220.   
  221. };   
  222.   
  223.     
  224.   
  225.   分析:tagMyStruct稱爲“tag”,即“標籤”,實際上是一個臨時名字,struct 關鍵字和tagMyStruct一起,構成了這個結構類型,不論是否有typedef,這個結構都存在。   
  226.   
  227.     
  228.   
  229.   我們可以用struct tagMyStruct varName來定義變量,但要注意,使用tagMyStruct varName來定義變量是不對的,因爲struct 和tagMyStruct合在一起才能表示一個結構類型。   
  230.   
  231.     
  232.   
  233.   2) typedef爲這個新的結構起了一個名字,叫MyStruct。   
  234.   
  235.     
  236.   
  237. typedef struct tagMyStruct MyStruct;   
  238.   
  239.     
  240.   
  241.   因此,MyStruct實際上相當於struct tagMyStruct,我們可以使用MyStruct varName來定義變量。   
  242.   
  243.     
  244.   
  245.   答案與分析   
  246.   
  247.     
  248.   
  249.   C語言當然允許在結構中包含指向它自己的指針,我們可以在建立鏈表等數據結構的實現上看到無數這樣的例子,上述代碼的根本問題在於typedef的應用。   
  250.   
  251.     
  252.   
  253.   根據我們上面的闡述可以知道:新結構建立的過程中遇到了pNext域的聲明,類型是pNode,要知道pNode表示的是類型的新名字,那麼在類型本身還沒有建立完成的時候,這個類型的新名字也還不存在,也就是說這個時候編譯器根本不認識pNode。   
  254.   
  255.     
  256.   
  257.   解決這個問題的方法有多種:   
  258.   
  259. 1)、   
  260.   
  261.     
  262.   
  263. typedef struct tagNode   
  264.   
  265. {   
  266.   
  267.  char *pItem;   
  268.   
  269.  struct tagNode *pNext;   
  270.   
  271. } *pNode;   
  272.   
  273. 2)、   
  274.   
  275.     
  276.   
  277. typedef struct tagNode *pNode;   
  278.   
  279. struct tagNode   
  280.   
  281. {   
  282.   
  283.  char *pItem;   
  284.   
  285.  pNode pNext;   
  286.   
  287. };   
  288.   
  289.     
  290.   
  291. 注意:在這個例子中,你用typedef給一個還未完全聲明的類型起新名字。C語言編譯器支持這種做法。   
  292.   
  293. 3)、規範做法:   
  294.   
  295.     
  296.   
  297. struct tagNode   
  298.   
  299. {   
  300.   
  301.  char *pItem;   
  302.   
  303.  struct tagNode *pNext;   
  304.   
  305. };   
  306.   
  307. typedef struct tagNode *pNode;   
  308.   
  309.     
  310.   
  311.     
  312.   
  313. C++中typedef關鍵字的用法   
  314.   
  315. Typedef 聲明有助於創建平臺無關類型,甚至能隱藏複雜和難以理解的語法。不管怎樣,使用 typedef 能爲代碼帶來意想不到的好處,通過本文你可以學習用 typedef 避免缺欠,從而使代碼更健壯。   
  316.   
  317.       typedef 聲明,簡稱 typedef,爲現有類型創建一個新的名字。比如人們常常使用 typedef 來編寫更美觀和可讀的代碼。所謂美觀,意指 typedef 能隱藏笨拙的語法構造以及平臺相關的數據類型,從而增強可移植性和以及未來的可維護性。本文下面將竭盡全力來揭示 typedef 強大功能以及如何避免一些常見的陷阱。   
  318.   
  319.       如何創建平臺無關的數據類型,隱藏笨拙且難以理解的語法?   
  320.   
  321.     
  322.   
  323. 使用 typedefs 爲現有類型創建同義字。定義易於記憶的類型名   
  324.   
  325.   typedef 使用最多的地方是創建易於記憶的類型名,用它來歸檔程序員的意圖。類型出現在所聲明的變量名字中,位於 ''typedef'' 關鍵字右邊。例如:typedef int size;   
  326.   
  327.   此聲明定義了一個 int 的同義字,名字爲 size。注意 typedef 並不創建新的類型。它僅僅爲現有類型添加一個同義字。你可以在任何需要 int 的上下文中使用 size:void measure(size * psz);   
  328.   
  329. size array[4];   
  330.   
  331. size len = file.getlength();   
  332.   
  333. std::vector <size> vs;   
  334.   
  335.   typedef 還可以掩飾符合類型,如指針和數組。例如,你不用象下面這樣重複定義有 81 個字符元素的數組:char line[81];   
  336.   
  337. char text[81];   
  338.   
  339. 定義一個 typedef,每當要用到相同類型和大小的數組時,可以這樣:typedef char Line[81];   
  340.   
  341. Line text, secondline;   
  342.   
  343. getline(text);   
  344.   
  345. 同樣,可以象下面這樣隱藏指針語法:typedef char * pstr;   
  346.   
  347. int mystrcmp(pstr, pstr);   
  348.   
  349.   這裏將帶我們到達第一個 typedef 陷阱。標準函數 strcmp()有兩個‘const char *'類型的參數。因此,它可能會誤導人們象下面這樣聲明 mystrcmp():int mystrcmp(const pstr, const pstr);   
  350.   
  351.   這是錯誤的,按照順序,‘const pstr'被解釋爲‘char * const'(一個指向 char 的常量指針),而不是‘const char *'(指向常量 char 的指針)。這個問題很容易解決:typedef const char * cpstr;   
  352.   
  353. int mystrcmp(cpstr, cpstr); // 現在是正確的   
  354.   
  355. 記住:不管什麼時候,只要爲指針聲明 typedef,那麼都要在最終的 typedef 名稱中加一個 const,以使得該指針本身是常量,而不是對象。代碼簡化   
  356.   
  357.   上面討論的 typedef 行爲有點像 #define 宏,用其實際類型替代同義字。不同點是 typedef 在編譯時被解釋,因此讓編譯器來應付超越預處理器能力的文本替換。例如:typedef int (*PF) (const char *, const char *);   
  358.   
  359.   這個聲明引入了 PF 類型作爲函數指針的同義字,該函數有兩個 const char * 類型的參數以及一個 int 類型的返回值。如果要使用下列形式的函數聲明,那麼上述這個 typedef 是不可或缺的:PF Register(PF pf);   
  360.   
  361.   Register() 的參數是一個 PF 類型的回調函數,返回某個函數的地址,其署名與先前註冊的名字相同。做一次深呼吸。下面我展示一下如果不用 typedef,我們是如何實現這個聲明的:int (*Register (int (*pf)(const char *, const char *)))   
  362.   
  363. (const char *, const char *);   
  364.   
  365.   很少有程序員理解它是什麼意思,更不用說這種費解的代碼所帶來的出錯風險了。顯然,這裏使用 typedef 不是一種特權,而是一種必需。持懷疑態度的人可能會問:"OK,有人還會寫這樣的代碼嗎?",快速瀏覽一下揭示 signal()函數的頭文件 <csinal>,一個有同樣接口的函數。typedef 和存儲類關鍵字(storage class specifier)   
  366.   
  367.   這種說法是不是有點令人驚訝,typedef 就像 auto,extern,mutable,static,和 register 一樣,是一個存儲類關鍵字。這並是說 typedef 會真正影響對象的存儲特性;它只是說在語句構成上,typedef 聲明看起來象 static,extern 等類型的變量聲明。下面將帶到第二個陷阱:typedef register int FAST_COUNTER; // 錯誤   
  368.   
  369.   編譯通不過。問題出在你不能在聲明中有多個存儲類關鍵字。因爲符號 typedef 已經佔據了存儲類關鍵字的位置,在 typedef 聲明中不能用 register(或任何其它存儲類關鍵字)。促進跨平臺開發   
  370.   
  371.   typedef 有另外一個重要的用途,那就是定義機器無關的類型,例如,你可以定義一個叫 REAL 的浮點類型,在目標機器上它可以i獲得最高的精度:typedef long double REAL;   
  372.   
  373. 在不支持 long double 的機器上,該 typedef 看起來會是下面這樣:typedef double REAL;   
  374.   
  375. 並且,在連 double 都不支持的機器上,該 typedef 看起來會是這樣:、typedef float REAL;   
  376.   
  377.   你不用對源代碼做任何修改,便可以在每一種平臺上編譯這個使用 REAL 類型的應用程序。唯一要改的是 typedef 本身。在大多數情況下,甚至這個微小的變動完全都可以通過奇妙的條件編譯來自動實現。不是嗎? 標準庫廣泛地使用 typedef 來創建這樣的平臺無關類型:size_t,ptrdiff 和 fpos_t 就是其中的例子。此外,象 std::string 和 std::ofstream 這樣的 typedef 還隱藏了長長的,難以理解的模板特化語法,例如:basic_string<char, char_traits<char>,allocator<char>> 和 basic_ofstream<char, char_traits<char>>。   
  378.   
  379.      
  380.   
  381.     
  382.   
  383.  typedef & #define的問題  有下面兩種定義pStr數據類型的方法,兩者有什麼不同?哪一種更好一點?typedef char *pStr;   
  384.   
  385. #define pStr char *;   
  386.   
  387.   答案與分析:   
  388.   
  389.   通常講,typedef要比#define要好,特別是在有指針的場合。請看例子:typedef char *pStr1;   
  390.   
  391. #define pStr2 char *;   
  392.   
  393. pStr1 s1, s2;   
  394.   
  395. pStr2 s3, s4;   
  396.   
  397.   在上述的變量定義中,s1、s2、s3都被定義爲char *,而s4則定義成了char,不是我們所預期的指針變量,根本原因就在於#define只是簡單的字符串替換而typedef則是爲一個類型起新名字。  #define用法例子:#define f(x) x*x   
  398.   
  399. main( )   
  400.   
  401. {   
  402.   
  403.  int a=6b=2,c;   
  404.   
  405.  c=f(a) / f(b);   
  406.   
  407.  printf("%d \\n",c);   
  408.   
  409. }   
  410.   
  411.   以下程序的輸出結果是: 36。   
  412.   
  413.   因爲如此原因,在許多C語言編程規範中提到使用#define定義時,如果定義中包含表達式,必須使用括號,則上述定義應該如下定義纔對:#define f(x) (x*x)   當然,如果你使用typedef就沒有這樣的問題。   
  414.   
  415.   4. typedef & #define的另一例  下面的代碼中編譯器會報一個錯誤,你知道是哪個語句錯了嗎?   
  416.   
  417. typedef char * pStr;   
  418.   
  419. char string[4] = "abc";   
  420.   
  421. const char *p1 = string;   
  422.   
  423. const pStr p2 = string;   
  424.   
  425. p1++;   
  426.   
  427. p2++;   
  428.   
  429.   答案與分析:   
  430.   
  431.   是p2++出錯了。這個問題再一次提醒我們:typedef和#define不同,它不是簡單的文本替換。上述代碼中const pStr p2並不等於const char * p2。const pStr p2和const long x本質上沒有區別,都是對變量進行只讀限制,只不過此處變量p2的數據類型是我們自己定義的而不是系統固有類型而已。因此,const pStr p2的含義是:限定數據類型爲char *的變量p2爲只讀,因此p2++錯誤。  #define與typedef引申談   
  432.   
  433.   1) #define宏定義有一個特別的長處:可以使用 #ifdef ,#ifndef等來進行邏輯判斷,還可以使用#undef來取消定義。   
  434.   
  435.   2) typedef也有一個特別的長處:它符合範圍規則,使用typedef定義的變量類型其作用範圍限制在所定義的函數或者文件內(取決於此變量定義的位置),而宏定義則沒有這種特性。   
  436.   
  437.   5. typedef & 複雜的變量聲明   
  438.   
  439.   在編程實踐中,尤其是看別人代碼的時候,常常會遇到比較複雜的變量聲明,使用typedef作簡化自有其價值,比如:   
  440.   
  441.   下面是三個變量的聲明,我想使用typdef分別給它們定義一個別名,請問該如何做?>1:int *(*a[5])(int, char*);   
  442.   
  443. >2:void (*b[10]) (void (*)());   
  444.   
  445. >3. doube(*)() (*pa)[9];   
  446.   
  447.   答案與分析:  對複雜變量建立一個類型別名的方法很簡單,你只要在傳統的變量聲明表達式裏用類型名替代變量名,然後把關鍵字typedef加在該語句的開頭就行了。>1:int *(*a[5])(int, char*);   
  448.   
  449. //pFun是我們建的一個類型別名   
  450.   
  451. typedef int *(*pFun)(int, char*);   
  452.   
  453. //使用定義的新類型來聲明對象,等價於int* (*a[5])(int, char*);   
  454.   
  455. pFun a[5];>2:void (*b[10]) (void (*)());   
  456.   
  457. //首先爲上面表達式藍色部分聲明一個新類型   
  458.   
  459. typedef void (*pFunParam)();   
  460.   
  461. //整體聲明一個新類型   
  462.   
  463. typedef void (*pFun)(pFunParam);   
  464.   
  465. //使用定義的新類型來聲明對象,等價於void (*b[10]) (void (*)());   
  466.   
  467. pFun b[10];>3. doube(*)() (*pa)[9];   
  468.   
  469. //首先爲上面表達式藍色部分聲明一個新類型   
  470.   
  471. typedef double(*pFun)();   
  472.   
  473. //整體聲明一個新類型   
  474.   
  475. typedef pFun (*pFunParam)[9];   
  476.   
  477. //使用定義的新類型來聲明對象,等價於doube(*)() (*pa)[9];   
  478.   
  479. pFunParam pa;   
  480.    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章