久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 15699|回復: 2
收起左側

c語言typedef & define用法介紹(非常詳細)

[復制鏈接]
ID:98924 發表于 2015-12-9 02:46 | 顯示全部樓層 |閱讀模式
1. 基本解釋

  typedef為C語言的關鍵字,作用是為一種數據類型定義一個新名字。這里的數據類型包括內部數據類型(int,char等)和自定義的數據類型(struct等)。

  在編程中使用typedef目的一般有兩個,一個是給變量一個易記且意義明確的新名字,另一個是簡化一些比較復雜的類型聲明。

  至于typedef有什么微妙之處,請你接著看下面對幾個問題的具體闡述。

2. typedef & 結構的問題

  當用下面的代碼定義一個結構時,編譯器報了一個錯誤,為什么呢?莫非C語言不允許在結構中包含指向它自己的指針嗎?請你先猜想一下,然后看下文說明:
typedef struct tagNode
{
 char *pItem;
 pNode pNext;
} *pNode;

  答案與分析:

  1、typedef的最簡單使用
typedef long byte_4;

  給已知數據類型long起個新名字,叫byte_4。

  2、 typedef與結構結合使用
typedef struct tagMyStruct
{
 int iNum;
 long lLength;
} MyStruct;

  這語句實際上完成兩個操作:

  1) 定義一個新的結構類型
struct tagMyStruct
{
 int iNum;
 long lLength;
};

  分析:tagMyStruct稱為“tag”,即“標簽”,實際上是一個臨時名字,struct 關鍵字和tagMyStruct一起,構成了這個結構類型,不論是否有typedef,這個結構都存在。

  我們可以用struct tagMyStruct varName來定義變量,但要注意,使用tagMyStruct varName來定義變量是不對的,因為struct 和tagMyStruct合在一起才能表示一個結構類型。

  2) typedef為這個新的結構起了一個名字,叫MyStruct。
typedef struct tagMyStruct MyStruct;

  因此,MyStruct實際上相當于struct tagMyStruct,我們可以使用MyStruct varName來定義變量。

  答案與分析

  C語言當然允許在結構中包含指向它自己的指針,我們可以在建立鏈表等數據結構的實現上看到無數這樣的例子,上述代碼的根本問題在于typedef的應用。

  根據我們上面的闡述可以知道:新結構建立的過程中遇到了pNext域的聲明,類型是pNode,要知道pNode表示的是類型的新名字,那么在類型本身還沒有建立完成的時候,這個類型的新名字也還不存在,也就是說這個時候編譯器根本不認識pNode。

  解決這個問題的方法有多種:

  1)、
typedef struct tagNode
{
 char *pItem;
 struct tagNode *pNext;
} *pNode;

  2)、
typedef struct tagNode *pNode;
struct tagNode
{
 char *pItem;
 pNode pNext;
};

  注意:在這個例子中,你用typedef給一個還未完全聲明的類型起新名字。C語言編譯器支持這種做法。

  3)、規范做法:
struct tagNode
{
 char *pItem;
 struct tagNode *pNext;
};
typedef struct tagNode *pNode;

3. typedef & #define的問題

  有下面兩種定義pStr數據類型的方法,兩者有什么不同?哪一種更好一點?
typedef char *pStr;
#define pStr char *;

  答案與分析:

  通常講,typedef要比#define要好,特別是在有指針的場合。請看例子:
typedef char *pStr1;
#define pStr2 char *;
pStr1 s1, s2;
pStr2 s3, s4;

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

  #define用法例子:
#define f(x) x*x
main( )
{
 int a=6,b=2,c;
 c=f(a) / f(b);
 printf("%d ",c);
}

  以下程序的輸出結果是: 36。

  因為如此原因,在許多C語言編程規范中提到使用#define定義時,如果定義中包含表達式,必須使用括號,則上述定義應該如下定義才對:
#define f(x) (x*x)

  當然,如果你使用typedef就沒有這樣的問題。

  4. typedef & #define的另一例

  下面的代碼中編譯器會報一個錯誤,你知道是哪個語句錯了嗎?
typedef char * pStr;
char string[4] = "abc";
const char *p1 = string;
const pStr p2 = string;
p1++;
p2++;

  答案與分析:

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

(注:關于const的限定內容問題,在本系列第二篇有詳細講解)。

  #define與typedef引申談

  1) #define宏定義有一個特別的長處:可以使用 #ifdef ,#ifndef等來進行邏輯判斷,還可以使用#undef來取消定義。

  2) typedef也有一個特別的長處:它符合范圍規則,使用typedef定義的變量類型其作用范圍限制在所定義的函數或者文件內(取決于此變量定義的位置),而宏定義則沒有這種特性。

  5. typedef & 復雜的變量聲明

  在編程實踐中,尤其是看別人代碼的時候,常常會遇到比較復雜的變量聲明,使用typedef作簡化自有其價值,比如:

  下面是三個變量的聲明,我想使用typdef分別給它們定義一個別名,請問該如何做?
>1:int *(*a[5])(int, char*);
>2:void (*b[10]) (void (*)());
>3. doube(*)() (*pa)[9];

  答案與分析:

  對復雜變量建立一個類型別名的方法很簡單,你只要在傳統的變量聲明表達式里用類型名替代變量名,然后把關鍵字typedef加在該語句的開頭就行了。

  (注:如果你對有些變量的聲明語法感到難以理解,請參閱本系列第十篇的相關內容)。
>1:int *(*a[5])(int, char*);
//pFun是我們建的一個類型別名
typedef int *(*pFun)(int, char*);
//使用定義的新類型來聲明對象,等價于int* (*a[5])(int, char*);
pFun a[5];

>2:void (*b[10]) (void (*)());
//首先為上面表達式藍色部分聲明一個新類型
typedef void (*pFunParam)();
//整體聲明一個新類型
typedef void (*pFun)(pFunParam);
//使用定義的新類型來聲明對象,等價于void (*b[10]) (void (*)());
pFun b[10];

>3. doube(*)() (*pa)[9];
//首先為上面表達式藍色部分聲明一個新類型
typedef double(*pFun)();
//整體聲明一個新類型
typedef pFun (*pFunParam)[9];
//使用定義的新類型來聲明對象,等價于doube(*)() (*pa)[9];
pFunParam pa;

//第1篇:typedef語句格式
#include
typedef int GTYPE;//定義全局類型GTYPE
void main()
{
//一、基本格式
typedef char CH;//重定義基本類型
typedef struct{int a,b,c;}STRU;//重定義自定義類型(結構、共用、枚舉)
typedef union{int a,b,c;}UNIO;
typedef enum{one,two,three}NUM;
typedef char* STR;//重定義派生類型(指針、數組、函數)
typedef int AI[10];
typedef void FUN(void);
//可見,typedef使用的格式為:typedef 變量/函數定義語句;即在原變量/函數定義語句的開頭加上
//typedef,便可將原變量/函數定義語句改寫為類型定義語句,原來定義的變量名/函數名都成了類型名。
//注:當重定義基本、自定義類型時,格式也可總結為:typedef 原類型 新類型1,新類型2,…;

//二、觀察原類型
//1.原類型可以帶有類型限定符
typedef const int CI;//原類型含const限定符
CI ci=3;
//ci=4;//可見CI確實代表const int

//2.原類型可以是typedef定義的新類型
typedef CH NEWCH;//CH已在前面定義為char
NEWCH nc='a';

//3.原類型不可帶有存儲類別
//typedef static int SI;//錯誤,"指定的存儲類多于1個"
//typedef register int RI;//錯誤同上

//4.原類型應是一種類型,而不可是變量/對象
float f=0;//將f定義為變量
//typedef f FL;//錯誤

//5.不宜重定義的類型
typedef const CON;//重定義const
//CON int a=0;//但該類型無法正常使用
typedef unsigned US;//重定義unsigned
US us1=0;//正確,相當于unsigned int
//US int us2;//錯誤,無法正常使用
//注:因const、unsigned等并不是一種獨立的類型,故不便對它們重定義

//三、觀察新類型
//1.新類型的作用域
typedef int LTYPE;//定義局部類型LTYPE
void fun();//觀察LTYPE在fun中是否有效
fun();
//可見,用typedef定義的類型也有作用域之分。在函數內用typedef定義的是局部類型
//typedef也可以像變量定義語句一樣放置在函數之外,這時定義的是全局類型

//2.新類型可否是已有類型
//typedef int float;//錯誤,不能重定義標準類型
typedef int TYPE; //定義了新類型TYPE
//typedef char TYPE;//錯誤,"TYPE重定義"
typedef int GTYPE;//正確,盡管GTYPE是已有類型,但它是本函數外定義的
//可見,新類型名必須是合法的標識符,它在其作用域內必須是唯一的

//3.新類型可否不止一個
typedef float LENGTH,WIDTH;//對float取兩個別名,LENGTH和WIDTH
LENGTH L=0;//用新類型定義變量
WIDTH W=0;
//可見,可以一次性為某個原類型指定多個別名

//4.一次可否定義多個不同類型
//typedef int I,float F;//一次定義了二個不同類型I和F
//F v=6.0;//試圖使用F類型
//printf("v=%f ",v);//v=0,類型F無效
//可見,一條typedef語句只宜為一個原類型定義別名

}
void fun()
{ //LTYPE i;//錯誤,"LTYPE:未定義的標識符"
GTYPE g=1;//使用全局類型GTYPE
printf("g=%d ",g);//正常使用
}
//第2篇:typedef詳細使用

/* 為了從易到難地使用typedef,現將C++數據類型按照類型名的來源和復雜性重分類如下:
一、基本類型(類型名是系統指定的單一標識符)
in,char,float,double,void,const
二、自定義類型(類型名是用戶定義的單一標識符)
1.結構類型
struct stru{int i;struct stru*;};
2.共用類型
union unio{int i;enum num[10];};
3.枚舉類型
enum num{a,b,c};
4.typedef類型
typedef double db;
三、派生類型(類型名由已有類型與其它符號組合而成)
1.指針類型(由 已有類型* 組成)
void*,char**,void(*)(),struct stru*,enum num*
2.數組類型(由 已有類型[][] 組成)
int[3][4],struct stru[10],enum num[10],char*[10]
3.函數類型(類型名是各種符號組成的函數原型)
void main(void),char* strcpy(char*,char*)

以上三大類別的類型標識符由簡單到復雜,學習typedef時要依照先后順序,練習每種類型的重定義
每定義出一種新類型后,從以下幾個方面使用它:用它定義變量、指針、數組、帶存儲類別的對象、
帶const的對象;用它作函數參數和返回值類型;用它進行類型轉換;用sizeof求長度*/

#include
#include
void main()
{
//一、重定義基本類型
//1.定義
typedef int in;
typedef char ch;
typedef float fl;
typedef double db;
typedef unsigned int ui;//或寫為typedef unsigned ui;
typedef unsigned char uc;
typedef void vo;

//2.使用
in i=3;printf("i=%d ",i); //用新類型定義變量
ch* pc="pc";printf("pc=%s ",pc);//用新類型定義指針
fl af[3]={1,2,3};printf("af[0]=%f ",af[0]);//用新類型定義數組
static double sd;printf("sd=%f ",sd);//用新類型定義帶存儲類別的變量
const ui cui=3;printf("cui=%d ",cui);//用新類型定義帶類型限定符的變量
vo fun1(uc);fun1('a');//用新類型作函數的參數和返回值類型
printf("in(1.5)=%d ",in(1.5));//將新類型用作類型轉換
printf("$db=%d ",sizeof(db));//對新類型求長度,$db=$double=8

//二、重定義自定義類型
//1.定義
//(1)完整寫法(先定義好自定義類型,再重定義它)
struct datetype //重定義結構類型
{ ui year;//ui即是unsigned int;
uc month;//uc即是unsigned char;
uc day;};
typedef datetype date;
union scoretype //重定義共用類型
{ fl sco1;
ch* sco2;};
typedef scoretype score;
enum numtype{one,two,three}; //重定義枚舉類型
typedef numtype num;
typedef num newnum; //重定義typedef類型

//(2)通常寫法(對無類型名的結構、共用、枚舉定義語句直接重定義)
typedef struct{uc hou,min,sec;} time;
typedef union{fl sco1;ch* sco2;} sco;
typedef enum{red,green,blue} color;
//可見,無論何種寫法,都遵循typedef語句的格式:typedef 原類型 新類型;

//2.使用
date vs={2002,10,15};//定義結構變量
printf("vs:%d.%d.%d ",vs.year,vs.month,vs.day);
score vu,*pu=&vu;printf("&vu=%x pu=%x ",&vu,pu);//定義共用指針
newnum ae[3]={one,two,three};//定義枚舉數組
printf("ae[0]=%d ae[1]=%d ae[2]=%d ",ae[0],ae[1],ae[2]);
static num vn;//定義帶存儲類別的對象
printf("vn=%d ",vn);
const sco cs={90};//定義const對象
printf("cs.sco1=%f ",cs.sco1);
time fun2(time);//作函數的參數和返回值類型
static time vt=fun2(vt);
printf("fun2:%d:%d:%d ",vt.hou,vt.min,vt.sec);
vn=(num)10;printf("vn=%d ",vn);//將新類型用作類型轉換
printf("$time=%d ",sizeof(time));//對新類型求長度,$time=3
printf("$sco=%d ",sizeof(sco));//對新類型求長度,$sco=4
printf("$color=%d ",sizeof(color));//對新類型求長度,$color=4

//第3篇:typedef具體應用

#include
int fun1(int a,int b){return 0;}
int fun2(int a,int b){return 0;}
int fun3(int a,int b){return 0;}
void main()
{ //一、使用typedef的優點
//1可以為現有類型取一個更有意義的名字,增加程序的可讀性,如
typedef char* STRING;
STRING s1="string1",s2="string2";//STRING便可當作字符串類型來使用

//2使變量定義更簡短,減少書寫麻煩,如
typedef float A3[2][3][4];//為2*3*4的實型數組取簡短的名字A3
A3 a,b,c;//相當于定義float a[2][3][4],b[2][3][4],c[2][3][4]
typedef unsigned int(*PFUN)(int(*)[4]);//PFUN是一種函數指針,該類函數參數為一維數組型指針,返回值為無符號整型
PFUN pf1,pf2;//相當于定義unsigned int(*pf1)(int(*)[4]);unsigned int(*pf2)(int(*)[4])

//3在定義復雜類型前,先用typedef建立一些中間類型,再用中間類型去構造復雜類型,以降低其復雜性(主要用途)
//例:對于如下的復雜定義
int(*ap[3])(int,int);//ap是一個數組,其元素為函數型指針,該類函數的參數和返回值都是整型
//采用typedef以降低定義難度
//方法1
typedef int(*PF)(int,int);//定義PF為該種函數的指針
PF ap1[3];//ap1為一數組,每個元素都是PF類型
ap1[0]=fun1;ap1[1]=fun2;ap1[2]=fun3;
//方法2
typedef int FUN(int,int);//將該種函數定義為FUN類型
FUN* ap2[3];//ap2為一數組,每個元素都是指向FUN的指針
ap2[0]=fun1;ap2[1]=fun2;ap2[2]=fun3;

//4增加程序的可移植性(有利于程序在不同處理器、操作系統和編譯系統之間的移植)
/*例如,在TC下讀文件的程序段如下:
FILE* fp;
long buffer1;
fread(&buffer1,sizeof(long),1,fp);//每次讀出4個字節
若在VC下每次需要讀出8個字節,程序需如下修改:
double buffer2;
fread(&buffer2,sizeof(double),1,fp);
現用typedef方法,程序段如下:
typedef long UNIT;//UNIT在TC中代表long,在VC中代表double
UNIT buffer;
fread(&buffer,sizeof(UNIT),1,fp);//每次讀出UNIT個字節
當移植到VC下時,只需改動UNIT的定義即可:typedef double UNIT;*/

//二、typedef與define的區別
//用define也可實現簡單的類型替換,如
#define INT long //用INT來代替long
//兩種方式的區別如下:
//1.二者處理時間不同,宏替換是在預編譯時進行的,而類型定義是在正式編譯時處理的
//2二者本質不同,宏替換只是將宏名簡單替換為目標字符串,而類型定義如同定義變量一樣
//是真的為程序增加了一種可用類型
//3.二者復雜性不同,用typedef可定義各種復雜的類型,并以各種方式使用新類型(詳見10_10_2.cpp)
//而define只能替換基本類型和自定義類型,無法替換派生類型,且使用起來很不安全,例如
#define pi int* //試圖用pi代替整型指針
pi pi1;//正確,展開后為int* pi1;
pi pi2,pi3;//錯誤,原意是將pi2,pi3都定義成整型指針,但展開后為int* pi2,pi3; pi3并未定義成指針

#define NUM enum{one,two,three}//試圖用NUM代替該枚舉類型
NUM n1;//正確,定義了枚舉常量one,two,three和枚舉變量n1
//NUM n2;//錯誤,展開后為enum{one,two,three}n2;從而造成枚舉常量one,two,three的重定義

#define DATE struct{int y,m,d;}
DATE *pd;//正確,定義了該結構型指針
//pd=(DATE)1;//錯誤,展開后為pi=(struct{int y,m,d;})1;目前尚不支持此種類型轉換寫法

#define TIME union{int h,m,s;}
//int L=sizeof(TIME);//錯誤,展開后為int L=sizeof(union{int h,m,s;});sizeof操作數錯誤
//可見,用define進行類型替換時,會產生各種意想不到的錯誤,故應避免使用,而改用安全的typedef

}
回復

使用道具 舉報

ID:99580 發表于 2015-12-19 21:04 | 顯示全部樓層
受教了。
回復

使用道具 舉報

ID:433680 發表于 2018-12-21 19:47 | 顯示全部樓層
學習了,感謝樓主了!!
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 国产一区免费 | 国产日韩欧美一区二区 | 亚洲www啪成人一区二区 | 亚洲精品一区二区三区蜜桃久 | 九九成人| 国产精品成人一区 | 国产在线一区二区 | 九九亚洲| 欧美视频免费 | 日韩在线欧美 | 中文字幕高清av | 国产精品特级毛片一区二区三区 | 免费一区二区三区 | 亚洲第1页 | 国产99精品 | 狠狠操狠狠干 | 蜜桃视频在线观看免费视频网站www | 91国内精精品久久久久久婷婷 | 农村黄性色生活片 | 久久专区| 97人人超碰| 成人在线视频观看 | 亚洲一区二区av | 久久久久久亚洲精品 | 欧美另类日韩 | 国产成人99久久亚洲综合精品 | 午夜小电影| 一区二区视频在线观看 | 国产精品综合色区在线观看 | 97精品超碰一区二区三区 | 亚洲欧美精品久久 | 99这里只有精品 | av在线播放网 | 亚洲精品日日夜夜 | 国产精品一区二区在线播放 | 亚洲欧美日韩精品久久亚洲区 | 国产一级电影在线 | 国产成人在线一区二区 | 国产美女一区二区 | 97精品国产97久久久久久免费 | 国产成人在线播放 |