zoukankan      html  css  js  c++  java
  • 详解typedef用法及define的区别

    1.typedef语法描述

         在现实生活中,信息的概念可能是长度、数量和面积等。在C语言中,信息被抽象为int、float和double等基本数据类型。从基本数据类型名称上,不能看出其所代表的物理属性,并且int、float和double为系统关键字,不可以修改。为了解决用户自定义数据类型名称的需求,C 语言中引入typedef,可以为数据类型创建别名,从而丰富数据类型所包含的属性信息。

    一般形式:

    typedef  类型名称  类型别名

    声明一个新的类型名的方法:

          1)  先按定义变量的方法写出定义体 ( 如:int i; )。

          2)  将变量名换成新的类型名 ( 将i换成COUNT )。

          3)  在最前面加typedef ( typedef int COUNT; )。

          4)  用新类型名去定义变量 ( COUNT num; )。

    说明:

           1.typedef为系统关键字,“类型名称”为已知数据类型名称,包括基本数据类型(如char、int)、UDT(如数组、struct);

           2. typedef为数据类型创建别名,而不是创建新的数据类型,可以对任何类型进行typedef声明。typedef是一种彻底的“封装”类型,在声明它之后就不能再往里面增加别的东西了。

           3.习惯上常把typedef声明的类型名用大写字母表示        

    typedef double LENGTH;  
    typedef unsigned int COUNT;
    创建了别名之后,可像基本数据类型那样定义变量

    例如:

    typedef unsigned int COUNT;  
    unsigned int b;  
    COUNT c;

    2.typedef主要应用形式

    2.1为基本数据类型创建新类型名

    例子:

    typedef unsigned int COUNT;
    typedef double AREA;
    COUNT age;
    AREA s;

    应用的主要目的:

            首先是丰富数据类型中包含的属性信息,

            其次是为了系统移植的需要,稍后详细描述

    2.2为UDT(结构体、公用体和枚举类型)创建简洁的类型名称

    例子:

    struct Point  
    {  
    double x;  
    double y;  
    double z;  
    };  
    struct Point oPoint1={100,100,0}; 
    struct Point oPoint2;
          其中结构体 struct Point 为新的数据类型,在定义变量的时候均要有保留字struct,而不能像int和double那样直接使用Point来定义变量

    如果经过如下的修改:

    typedef struct tagPoint  
    {  
     double x;  
     double y;  
     double z;  
    } Point;  
    使用typedef之后,定义变量简化为
    Point oPoint;

    2.3为数组创建简洁的类型名称

    例如:

    int a[10], b[10], c[10];
            在C语言中,可以将长度为10的整型数组看作为一个数据类型,再利用typedef为其重定义一个新的名称,可以更加简洁形式定义此种类型的变量,具体的处理方式如下:
    typedef int INT_ARRAY_10[10];  
    typedef int INT_ARRAY_20[20];  
    
    INT_ARRAY_10 a,b,c,d;  
    INT_ARRAY_20 e;
           其中INT_ARRAY_10 和 INT_ARRAY_20为新的类型名,10和20 为数组的长度。a,b,c,d 均是长度为 10 的整型数组,e 是长度为 20 的整型数组。

    2.4为指针定义简洁的名称

            首先,为数据指针定义新的名称,在连续几个变量的声明中,用typedef定义的类型能够保证声明中的所有变量均为同一种类型如下:

    typedef char * STRING;
    STRING csName = “Jhon”;
    其次,也可以为函数指针定义新的名称

    typedef int (*MyFUN)(int a,int b);  
    
    int Max(int a,int b);  
    
    MyFUN pMyFun;  
    pMyFun = Max; 
    其中 MyFUN 代表  int XFunction(int a,intb)类型的函数指针的新名称。

    3.typedef 的三个用途和两个陷阱 

      用途一

             定义一种类型的别名,而不只是简单的宏替换,可以用作同时声明指针型的多个对象。

    typedef char * PCHAR;
    
    PCHAR pa, pb;//同时声明了两个指向字符变量的指针
    在大量使用指针的地方typedef更加方便

    用途二

    用 typedef 来定义与平台无关的类型。

    typedef long double REAL; 

    在不支持 long double 的平台二上,改为:    

    typedef double REAL;  

           当跨平台时,只要改下typedef本身就行,不用对其他源码做任何修改,标准库就广泛使用了这个技巧,比如size_t。另外,因为 typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健。

    用途三

           为复杂的声明定义一个新的简单的别名,举例:

    1. 原声明:int *(*a[5])(int, char*);

            变量名为 a,直接用一个新别名 pFun 替换 a 

    typedef int *(*pFun)(int, char*); 

           原声明的最简化版:

    pFun a[5]; 

           理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:

    int (*func)(int *p);

    分析:

           先找到变量名 func,外面有一对圆括号,而且左边是一个*号,这说明 func 是一个指针;然后跳出这个圆括号,先看右边,又遇到园括号,这说明  (*func)是一个函数,所以 func 是一个指向这类函数的指针,即函数指针,这类函数具有 int*类型的形参,返回值类型是 int。

    int (*func[5])(int *); 

    分析:
           func 右边是一个[]运算符,说明 func 是具有 5 个元素的数组;func 的左边有一个*,说明 func 的元素是指针(注意这里的*不是修饰func,而是修饰 func[5]的,原因是[]运算符优先级比*高,func 先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明 func 数组的元素是函数类型的指针,它指向的函数具有 int* 类型的形参,返回值类型为 int。

    陷阱一

    记住,typedef 是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。可以看作是一种彻底的“封装”

    例子:

    typedef char * PSTR;
    #define DEFCHAR char*
      ....
    char string[10] = "abcde";
     
    const DEFCHAR p1 = string;//字符首地址
    const PSTR p2 = string;
    
    p1++; //ok
    p2++; //error
    printf("%c %c
    ",*p1,*p2);

           通过编译运行可知:p2++出错。 

    分析:     

         这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。

         上述代码中“第一个const”修饰的是“p1指向的对象,不能通过*p1改变对象的内容”;“第二个const”修饰的是“p2本身,p2是常量”const pStr p2并不等于const char * p2。const PSTR p2和const long x本质上没有区别,认为都是对变量进行只读限制;为了容易理解,可以把PSTR当作基本类型”来处理,只不过此处的基本类型是我们自己定义的而不是系统固有类型。因此,const PSTR p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。

    陷阱二

           typedef 在语法上是一个存储类的关键字(如 auto、extern、static、register),但它并不真正影响对象的存储特性,如:    

    typedef static int INT2; //error,指定了一个以上的存储类  

    3.typedef与define的区别

         1)#define是预处理指令,主要定义常量,此常量可以为任何的字符及其组合;在编译预处理时进行简单的替换,不作正确性检查,不关含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错。例如:

    #define PI 3.1415926

          程序中的:area=PI*r*r  会替换为 3.1415926*r*r ;如果你把#define 语句中的数字9写成字母g预处理也照样带入。

       2)typedef是在编译时处理的。它在自己的作用域内给一个已经存在的类型一个别名。

       3)#define在预处理时进行简单的替换,而 typedef不是简单替换 。例如:

    #define int_ptr int *    
    int_ptr a, b; //相当于int * a, b;只是简单的宏替换 
    ....
    typedef int* int_ptr;    
    int_ptr a, b; //a, b 都是指向int的指针,

       4)也许您已经注意到#define不是语句,不要在行末加分号,否则会连分号一块置换;而typedef是声明语句,有分号。




  • 相关阅读:
    搭建第一个web项目:Struts+hibernate+spring配置(annotation)
    Visual Studio
    Javascript的性能瓶颈
    导出数据库文档的最简单的方式
    long类型在C#和C++中的异同
    GDI+创建Graphics对象的2种方式
    jQuery中click()与trigger方法的区别
    使用VS调试64位应用程序
    ASP.NET中多个相同name的控件在后台正确取值
    js中的eval方法转换对象时,为何一定要加上括号?
  • 原文地址:https://www.cnblogs.com/jinxiang1224/p/8468450.html
Copyright © 2011-2022 走看看