zoukankan      html  css  js  c++  java
  • define和typedef

    参考: 【C++】define 和typedef 的详细区别   define与typedef区别与联系

    #define(宏定义)只是简单的字符串代换(原地扩展),它本身并不在编译过程中进行,而是在这之前(预处理过程)就已经完成了。

    typedef是为了增加可读性而为标识符另起的新名称(仅仅只是个别名),它的新名字具有一定的封装性,以致于新命名的标识符具有更易定义变量的功能,它是语言编译过程的一部分,但它并不实际分配内存空间。

    一般都遵循#define定义“可读”的常量以及一些宏语句的任务,而typedef则常用来定义关键字、冗长的类型的别名。

    typedef是语句( 以';'结尾),而#define不是语句( 不以';'结尾)

    typedef int * int_ptr;
    #define INT_PTR int *
    const int_ptr p; //p不可更改,但p指向的内容可更改
    const INT_PTR p; //p可更改,但是p指向的内容不可更改
    int_ptr是一种类型(类型本身就是整型指针),const int_ptr p就是把指针给锁住了p不可更改,而const INT_PTR p是const int * p锁的是指针p所指的对象。这些使用常常使我迷惑,所以搜集整理对他们的理解如下:

    #define的用法:

    1、简单的宏定义 #define MAXTIME 1000一个简单的MAXTIME就定义好了,它代表1000,如果在程序里面写:
    if(i<MAXTIME){}编译器在处理这个代码之前会对MAXTIME进行处理替换为1000。
    这样的定义看起来类似于普通的常量定义const,但也有着不同,因为define的定义只是简单的替换,而不是作为一个量来使用,这个问题在下面反映的尤为突出。

    2、带参数的宏
    define可以像函数那样接受一些参数,如下:

    #define max(x,y) (x)>(y)?(x):(y);
    它将返回两个数中较大的那个,这个“函数”没有类型检查,就好像一个函数模板似的,当然,不难看出它绝对没有模板那么安全。
    因为这样做的话存在隐患,例子如下:

    #define Add(a,b) a+b;
    一般的单独使用是没有问题的,但是如果遇到如:c * Add(a,b) * d的时候就会出现问题,代数式的本意是a+b然后和c,d相乘,但是因为使用了define(它只是一个简单的替换),所以式子实际上变成了c*a + b*d 。
    再看看这个例子:

    #define int_ptr int *;
    int_ptr a,b;
    本意是a和b都是int型指针,但是实际上变成
    int* a,b;
    a是int型指针,而b是int型变量。这时应该使用typedef定义:
    typedef int* int_ptr;
    int_ptr a,b;
    这样a和b就都是int型指针了。

    3、define的多行定义
    define可以替代多行的代码,例如MFC中的宏定义(非常的经典,虽然让人看了恶心)

    #define MACRO(arg1, arg2) do { /
    /
    stmt1; /
    stmt2; /
    /
    } while(0) 
    关键是要在每一个换行的时候加上一个"/"。

    4、在大规模的开发过程中,特别是跨平台和系统的软件里,define最重要的功能是条件编译。

    #ifdef WINDOWS


    #endif
    #ifdef LINUX


    #endif
    可以在编译的时候通过#define设置编译环境

    5、如何定义宏、取消宏

    //定义宏
    #define [MacroName] [MacroValue]
    //取消宏
    #undef [MacroName]
    //普通宏
    #define PI (3.1415926)
    //带参数的宏
    #define max(a,b) ((a)>(b)? (a),(b))
    关键是十分容易产生错误,包括机器和人理解上的差异等等。

    6、条件编译
    #ifdef XXX…(#else) …#endif
    例如:

    #ifdef DV22_AUX_INPUT
    #define AUX_MODE 3
    #else
    #define AUY_MODE 3
    #endif


    1) #define是预处理指令,在编译预处理时进行简单的替换,不作正确性检查,不管含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错。例如:
    #define PI 3.1415926
    程序中的:area=PI*r*r 会替换为3.1415926*r*r
    如果你把#define语句中的数字9 写成字母g 预处理也照样带入。

    2)typedef是在编译时处理的。它在自己的作用域内给一个已经存在的类型一个别名,但是You cannot use the typedef specifier inside a function definition。

    3)typedef int * int_ptr;

    #define int_ptr int *
    作用都是用int_ptr代表 int * ,但是二者不同,正如前面所说 ,#define在预处理时进行简单的替换,而typedef不是简单替换,而是采用如同定义变量的方法那样来声明一种类型。也就是说;

    //refer to (xzgyb(老达摩))
    #define int_ptr int *
    int_ptr a, b; //相当于int * a, b; 只是简单的宏替换

    typedef int* int_ptr;
    int_ptr a, b; //a, b 都为指向int的指针,typedef为int* 引入了一个新的助记符


    这也说明了为什么下面观点成立
    //QunKangLi(维护成本与程序员的创造力的平方成正比)
    typedef int * pint ;
    #define PINT int *

    那么:
    const pint p ;//p不可更改,但p指向的内容可更改
    const PINT p ;//p可更改,但是p指向的内容不可更改。

    pint是一种指针类型 const pint p 就是把指针给锁住了 p不可更改
    而const PINT p 是const int * p 锁的是指针p所指的对象。

    3)也许您已经注意到#define 不是语句不要在行末加分号,否则会连分号一块置换。
    4)也许您已经注意到#define不是语句,不要在行末加分号,否则会连分号一块置换;但是typedef结束必须加分号,因为它是语句。


    typedef只是为了增加可读性而为标识符另起的新名
    #define原本在C中是为了定义常量,const、enum、inline的出现使它也渐渐成为了起别名的工具

    为了尽可能地兼容,一般都遵循:
    #define定义“可读”的常量以及一些宏语句的任务(包括无参量与带参量)
    typedef则常用来定义关键字、冗长的类型的别名。


    陷阱一:
    记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。比如:
    先定义:
    typedef   char*   PSTR;
    然后:
    int   mystrcmp(const   PSTR,   const   PSTR);

    const   PSTR实际上相当于const   char*吗?不是的,它实际上相当于char*   const。
    原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char*   const。
    简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换就行。

    陷阱二:
    typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如:
    typedef   static   int   INT2;   //不可行
    编译将失败,会提示“指定了一个以上的存储类”。

    =================typedef使用大全(结构体)

    typedef struct _TS1{
        int x, y;
    } TS1, *PTS1, ***PPPTS1; // TS1是结构体的名称,PTS1是结构体指针的名称
    // 也就是将结构体struct _TS1 命名为TS1,
    // 将struct _TS1 * 命名为 PTS1
    // 将struct _TS1 *** 命名为 PPPTS1

    typedef struct { // struct后面的结构体说明也可以去掉
        int x, y;
    } TS2, *PTS2;

    typedef PTS1 *PPTS1; // 定义PPTS1是指向PTS1的指针

    typedef struct _TTS1{
        typedef struct ITTS1 {
            int x, y;
        } iner;
        iner i;
        int x, y;
    } TTS1;

    //结构体内部的结构体也一样可以定义
    typedef TTS1::ITTS1 ITS1;


    void test_struct()
    {
        // 基本结构体重定义的使用
        TS1 ts1 = {100, 200};
        PTS1 pts1 = &ts1; // 完全等价于TS1* pts1 = &ts1;
        PPTS1 ppts1 = &pts1; // 完全等价于TS1** ppts1 = &pts1;
        PPPTS1 pppts1 = &ppts1; // 完全等价于 TS1*** pppts1 = &ppts1;

        TS2 ts2 = {99, 88};
        PTS2 pts2 = &ts2;   // 完全等价于 TS2* pts2 = &ts2;

        TTS1 itts1 = {{110, 220}, 10, 20};
        Its1* rits1 = &itts1.i;
        ITS1* &its1 = rits1; // 等价于 TTS1::ITTS1 *its1 = &(itts1.i);
     

  • 相关阅读:
    openfiler的介绍与使用
    linux磁盘修复(home或者其他目录无法进入,系统进入emergency mode)
    安装centos系统时出现dracut-initqueue time out 报错
    Linux中sz与rz命令
    /etc/passwd与/etc/shadow
    两台设备做DNS主从同步部署(含正向解析与方向解析)
    通过xftp传输文件失败的解决方法
    /etc/hosts与/etc/resolv.conf区别
    /etc/nsswitch.conf配置文件--服务搜索顺序
    docker学习笔记
  • 原文地址:https://www.cnblogs.com/codings/p/3601089.html
Copyright © 2011-2022 走看看