#define和typedef

#define是宏定义,关键词:替换。如果定义的时候忘记了括号,或者没有注意指针*,就会给程序带来意想不到的错误;typedef是为一个类型重新起一个名字,关键词:rename.这两者在实际当中存在哪些陷阱呢?常见的陷阱我就不再介绍了,只总结我们不常注意的陷阱,而这些陷阱又是足以致命的。

1. 先来看一个宏定义:#define PCHAR char*

问题:p3和p4有什么不同?
分析:

      宏定义的关键是替换,所以定义语句被替换为:
      char *p3,p4;
答案:p3是char *类型,而p4为char类型。

 

2. 接着我们看一个数据结构的定义:

typedef struct student
{
    //  code
}Stu_st,*Stu_pst;
问题:
a. struct student *stu;还可以怎么表示?
分析:我们把struct student{ // }看成一个整体,给struct student{ // }取了一个别名“Stu_st”,同时给struct student{ // } *取了一个别名“Stu_pst”。

答案:Stu_pst stu; Stu_st *stu;
b. const Stu_pst stu中,const修饰的对象是谁?
分析:是stu3吗?答案不是,那修饰的是谁?回顾一下const int *p;和int * const p是不一样的,前者表示p指向的对象不可以变,而p的地址是可以变的,后者表示p的地址不可以变,而对象可以改变。从而我们把Stu_pst(也就是struct student{//} *)看做一个数据类型,视而不见。从而就相当于:const (...*) stu;“()”内的部分包括*号都被忽视了,从而const直接修饰stu这个指针,表示这个指针不能变,指针指向的对象可以变。我们不如换一种方式表示,这样更清楚:Stu_pst const stu;显然是修饰指针stu的。从而这两种方式都不能进行stu++或者stu--操作。

注意:我们很容易把此类问题和const int *p结合起来,错误认为const (...*)stu;应该为对象不能变,地址可以变,可以进行stu++或者stu--操作,其实对于编译器来讲,它只认为Stu_pst只是一个基本类型, const Stu_pst stu;  Stu_pst const stu; 表示同一个意思,相当于const int a;和int const a;结构体指针为只读指针,不能修改器指向,但可以修改其指向的内容。

Stu3++; Stu4++; 编译器都会报错,下面是详细解释:

下面再把typedef 与const 放在一起看看:
C) const Stu_pst stu3;
D) Stu_pst const stu4;
大多数初学者认为

C)里const 修饰的是stu3 指向的对象;

D)里const 修饰的是stu4这个指针。

很遗憾,C)里const 修饰的并不是stu3 指向的对象。那const 这时候到底修饰的是什么呢?

我们在讲解const int i 的时候说过const 放在类型名“int”前后都行;而const int*p 与int * const p 则完全不一样。也就是说,我们看const 修饰谁都时候完全可以将数据类型名视而不见,当它不存在。反过来再看“const Stu_pst stu3”,Stu_pst 是“struct student{ /*code*/} *”的别名, “struct student {/*code*/} *”是一个整体。对于编译器来说,只认为Stu_pst 是一个类型名,所以在解析的时候很自然的把“Stu_pst”这个数据类型名忽略掉。
现在知道const 到底修饰的是什么了吧?^_^。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值