typedef 与 #define的区别
typedef 与 #define的区别
整理于一篇经典blog,经典原文地址http://www.cnblogs.com/csyisong/archive/2009/01/09/1372363.html
案例一:
通常讲,typedef要比#define要好,特别是在有指针的场合。请看例子:
typedef char *pStr1;
#define pStr2 char *;
pStr1 s1, s2;
pStr2 s3, s4;
在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字。
案例二:
下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?
typedef char * pStr;
char string[4] = "abc";
const char *p1 = string;
const pStr p2 = string;
p1++;
p2++;
============解释1:
是p2++出错了。这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。上述代码中const pStr p2并不等于const char * p2。const pStr p2和const long x本质上没有区别,都是对变量进行读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此,const pStr p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。
读不懂上面这段话是么,
其实也可以多读几次嘛。。
const pStr p2和const long x本质上没有区别,都是对变量进行只读限制。x是一个常量。它初始话之后是不可以改变的。
const pStr p2的含义是:限定数据类型为char *的变量p2为只读。
就可以理解为p2是一个常量。p2自身是不可以改变的。但它的类型是pStr是一个char *,说明它指向的数据是char,不是const char。说明p2指向的数据是可改的。。
============解释2:
const char *p1 = string; 你可以这样理解:(const char) *p1 = string, p1是一个指针,指向const char的东西,这个东西就是string(string是一个字符数组的首地址,它的地址声明后肯定是const的,除非该数组销毁),但是p1是一个指针变量,它是可以递增的,即你看到的p1++,它可以完成从数组的来遍历数组的目的。
而const pStr p2 = string;是这样的:由于p2不是指针,const直接修饰到了p2,即现在的p2是常量了,它的类型是pStr(我们自己定义的类型),相当于const int p2, const long p2等等,const都是直接修饰p2的,只不过int,long是系统类型,而pStr是我们定义的类型。为什么会出现这种效果了,就是因为typedef,它把char *定义成一个复合的类型,要从整体上来理解语义,而不是字符替换后来理解语义。
============解释3:
onst char *p1 = string 意思是说一个指向const char类型的指针。。
p1指针是一个变量。他可以指向任意的char对象。就算不是const定义的char也可以,p1可以指向不同的char对象,因为他是一个变量。但他无论是指向const char对象还是char对象。都不能改变其指向对象的值。就是说上例子p1不能对string做修改。只能读取string的值。
而
typedef char *pStr
const pStr p2 = string 这里是typedef和指针共用时的坑爹指出。
const pStr p2 = string
pStr const p2 = string
char* const p2 = string 上面3个语句是一个意思。
就是说p2是一个指向非const、char类型的对象的const指针。p2初始化之后就不能够指向第二个对象。但p2可以对string的值进行修改。。
看到这里你可能会觉得这不是说p2++正确么~那么请继续看解释~
p2++是错的。。p2本来就是一个指针。。而且是一个const。。就是说是一个常量指针。。你觉得一个const常量初始化之后还可以++吗。。。上面的解释是错的。。不知道是看什么书的。。你可以弄个程序看看。。我贴一下我刚才test的代码。。
#include<stdio.h>
int main(){
typedef char * pStr;
char string[4] = "abc";
const char *p1 = string;
const pStr p2 = string;
p1++;
p2[2] = 'e';
printf(p1);
printf(p2);return 0;
}
p2指针可以对string进行修改。。可以p2不能动。。他是一个const常量!!!!!!!!!!!!!!!
但是p1可以移动。。但是p1却不能修改。。p2可以改。。可是不能移动。。我不懂怎么把指针的++操作说成了对char数组的操作了。。。
下面是代码。。我是用VS2010测试的。。不知道其他的编译器怎么样。。
#include<stdio.h>
int main(){
typedef char * pStr;
char string[4] = "abc";
const char *p1 = string;
const pStr p2 = string;
p1[1] = 'f';
p1++;
p2[2] = 'e';
p2++;
printf(p1);
printf(p2);
return 0;
}
下面是错误:
1>c:\test\typedef.cpp(8): error C3892: “p1”: 不能给常量赋值
1>c:\test\typedef.cpp(11): error C3892: “p2”: 不能给常量赋值
****
按我朋友的理解,const pStr p2 其中,const修辞的是pStr,而pStr类型实际上还是指针,所以这行是定义了一个常指针。可以理解为定义p2是指向char的常指针,常指针的话,p2++当然就不行。
***
============解释:4:
对 案例二 测试:
typedef.c:51:5: 错误: 向只读位置‘*p1’赋值
typedef.c:52:5: 错误: 令只读变量‘p2’自增
我对char * p的理解:两个部分,char为指向的值,p为指针变量,*只是做声明;
当const char * p1时,const修饰的是char,所以p1不能修改指向的值;
当const PStr p2时,const修饰的是p2,所以p2不能对自身做任何修改;
typedef相当于创建了一个新类型,只能做为整体来看。
============解释5:
其实,在这里主要就是对const的作用范围的理解。
typedef char * pStr;
char string1[4] = "abc";
char string2[4] = "def";
const char *p1 = string1;
const pStr p2 = string1;
p1[1] = 'f'; // 此句错
p1++; // 此句对
p1 = string2; // 此句对
p1[1] = 'x'; // 此句错
p2[1] = 'f'; // 此句对
p2++; // 此句错
p2 = string2; // 此句错
在const char *p1中,const的作用力量在p1所指的内容,也就是说,当p1指向string1时,string1的内容相对于p1来说是常量,是固定的,是不能改变的,所以p1[1] = 'f'这一句就是错误的,而p1自身的值(即地址值)是可以改变的,所以p1++和p1 = string2都是正确的。
在const pStr p2中,const的作用力量在p2,即p2是个常量,p2的值实际上是个地址,也就是说,p2已经固定了,它的值是不能变的,但它这个地址所指的内容是可以改变的,所以p2[1] = 'f'是对的,但p2 = string2是错误的,因为这句是想将另一个地址赋值给p2。
总体来说,一个是将内容固定为常量,一个是将地址固定为常量,也就是指针常量和常量指针的说法,p1是常量指针,p2是指针常量。这也是C中指针的魅力所在。
****插入语:
只看const 先不换typedef const修饰的是*p1 也就是说*p1这个值不能动 即不能赋值 const修饰的是p2,也就是说p2不能动 但*p2可以赋值
error C3892: 'p2' : you cannot assign to a variable that is const
看一下这个vs2008的错误就应该明白了吧,把这个类型当成系统定义的类型我觉得就比较好理解了,好比:
const int a = 5;
a++;
编译错误的道理是一样的。
******
大家共同进步哦~~
经典原文地址http://www.cnblogs.com/csyisong/archive/2009/01/09/1372363.html
typedef 与 #define的区别的更多相关文章
- typedef 和 #define 的区别
本文已迁移至: http://www.danfengcao.info/c/c++/2014/02/25/difference-between-define-and-typedef.html typed ...
- typedef与#define的区别
1. typedef typedef故名思意就是类型定义的意思,但是它并不是定义一个新的类型而是给已有的类型起一个别名,在这一点上与引用的含义类似,引用是变量或对象的别名,而typedef定义的是类 ...
- typedef 和define的区别
总结一下typedef和#define的区别 1.概念 #define 它在编译预处理时进行简单的替换,不作正确性检查.它是预处理指令. typedef 它在自己的作用域内给一个已经存在的类型一个别名 ...
- typedef 与define 的区别
typedef和#define的用法与区别 typedef和#define的用法与区别 一.typedef的用法 在C/C++语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译 ...
- typedef和#define的区别
转自:http://www.cnblogs.com/kerwinshaw/archive/2009/02/02/1382428.html 一.typedef的用法在C/C++语言中,typedef常用 ...
- C++中typedef和define的区别
typedef和#define的用法与区别 一.typedef的用法 在C/C++语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间,实例像: ...
- C++ 系列:typedef 和 #define 的区别
总结一下typedef和#define的区别 1.概念 #define 它在编译预处理时进行简单的替换,不作正确性检查.它是预处理指令. typedef 它在自己的作用域内给一个已经存在的类型一个别名 ...
- typedef 与 define 的区别
1.区别 (1)定义.执行时间.作用域 定义.执行时间: #define pchar char * typedef char *pchar; 定义的格式差别,显而易见的,要注意,define 是不能存 ...
- C语言中的typedef跟define的区别
今天用C语言练习时涉及到了typedef和define的使用问题,那么他们的区别是啥?这种情况下为什么要用typedef?哪种情况下为什么要用define呢? 学习C的时候的你是否考虑过这个问题呢? ...
随机推荐
- Alpha 冲刺报告3
队名 massivehard 组员一(组长:晓辉) 今天完成了哪些任务 .整理昨天的两个功能,补些bug 写了一个初步的loyaut github 还剩哪些任务: 后台的用来处理自然语言的服务器还没架 ...
- 关于vue项目管理项目的架构管理平台
关于vue项目管理项目的架构管理平台 https://panjiachen.github.io/vue-element-admin-site/#/zh-cn/faq 31.4k 次浏览 完整项目地址: ...
- 【bzoj5166】[HAOI2014]遥感监测 贪心
题目描述 给出平面上 $n$ 个圆,在x轴上选出尽可能少的点,使得每个圆中至少有一个点.求这个最小点数. 输入 第1行: N R 分别表示激光点的个数和射电望远镜能检测到的半径 第2~N+1行: Xi ...
- ava8并发教程:Threads和Executors
原文地址 原文作者:Benjamin Winterberg 译者:张坤 欢迎阅读我的Java8并发教程的第一部分.这份指南将会以简单易懂的代码示例来教给你如何在Java8中进行并发编程.这是一系列教 ...
- mysql查看表中列信息
查看所有数据库中所有表的数据库名和表名 SELECT `TABLES`.`TABLE_SCHEMA`, `TABLES`.`TABLE_NAME` FROM `information_schema`. ...
- 【刷题】HDU 3435 A new Graph Game
Problem Description An undirected graph is a graph in which the nodes are connected by undirected ar ...
- 【NOI 2018】归程(Kruskal重构树)
题面在这里就不放了. 同步赛在做这个题的时候,心里有点纠结,很容易想到离线的做法,将边和询问一起按水位线排序,模拟水位下降,维护当前的各个联通块中距离$1$最近的距离,每次遇到询问时输出所在联通块的信 ...
- loj2538 「PKUWC2018」Slay the Spire 【dp】
题目链接 loj2538 题解 比较明显的是,由于强化牌倍数大于\(1\),肯定是能用强化牌尽量用强化牌 如果强化牌大于等于\(k\),就留一个位给攻击牌 所以我们将两种牌分别排序,企图计算\(F(i ...
- 20135239 益西拉姆 linux内核分析 可执行程序的装载
益西拉姆 + 原创作品请勿转载 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” week 7 可 ...
- android与H5互相调用
市面上很多android软件都有内嵌H5的,主要是为了节约成本,提高开发效率,其实现原理主要是通过Java代码和JavaScript代码的互相调用来实现. Java调用Js 1,webview初始化: ...