关于使用typedef和const要注意的问题~
先声明一下,这贴先把const和typedef的基础用法忽略掉,基础用法可以参考网上资料~在讲解之前再声明这篇我本人也是带着疑点进行讲解的,还需要向有经验的前辈请教学习~
先来看一个问题
typedef void* P;
const P p=&data;
这个const应该是修饰p还是*p呢?~
正常来说把P的数据类型展开应该是修饰*p,但实际上却是修饰 p的(以下代码为证)
(编译运行环境我用手机c4droid测试)
程序代码:
#include<stdio.h> typedef void* P; int main( void ) { int data=3; const P p=&data; *p=2; printf("%d\n",data); return 0; }
运行结果:
2
但是如果改成const P p;p=&data;这样就会报错(退一步来说就算不报错也会警告)
为什么呢,现在再看一个例子
程序代码:
#include<stdio.h> typedef const void* P; int main( void ) { int data=3; P p=&data; *p=2; printf("%d\n",data); return 0; }
这样编译器报错!
很显然这样const是修饰*p的~
显然const不会把typedef的函数类型展开的~
现在再看下一个例子
程序代码:
#include<stdio.h> typedef void* P; void test1(const void* p){} void test2(void*const p){} void test3(const void* const p){} int main( void ) { const int data=3; P p=NULL; test1(p); test2(p); test3(p); p=&data; return 0; }
这段代码能编译没有产生警告或者错误么么,表面看上去没有,但实际上p=&data这里会产生数据类型不匹配的警告,
也就是说void* p的数据类型不能直接依赖于编译器转化为const int*,也就是说用const修饰和不用const修饰的数据类型还是不同的,但问题来了,test1,test2,test3这三个测试函数可以正常通过编译,这表明在调用函数处理的时候可以把void* 转化为const void* ,void* const 和const void* const这三种函数类型~
问题到这里还没有结束,接下来再看下面这段测试代码
程序代码:
#include<stdio.h> typedef void** P; void test1(const void** p){} void test2(void*const* p){} void test3(void** const p){} int main( void ) { P p=NULL; test1(p); test2(p); test3(p); return 0; }
据上面结论编译器调用函数时可以简单地强制转型为三种const类型,但这段代码编译时出乎意料地卡在在第一个测试函数,也就是说调用函数对const的处理能力是有限的,不要指望它能解决万能的const问题,除非人为强制转型再传递给函数~
这意味着如果函数涉及到const的处理的情况就要好好琢磨数据类型了,那如果调用函数时不打算自己强制转型但也要达到const* void*效果那怎么办呢,答案很耐人寻味 看下面的一种解决方案就知道了~
程序代码:
#include<stdio.h> typedef void* P; void test1(const void* P){} void test2(void*const* p){} void test3(void** const p){} int main( void ) { P* p=NULL; test1(p); test2(p); test3(p); return 0; }
这段代码能正常通过编译,还是利用const 对typedef处理的性质,由于const不会对typedef的具体类型进行展开,所以调用函数时把P看成一个整体,这就可以了~
上面弄完或者会说好玩罢了,其实细细品味却体现出如何用好typedef,并且说明了函数参数解析类型最好不要过于复杂,复杂的数据类型应该用typedef处理~
总结一下就是基本函数参数类型最佳就只含有几种结构
fun(ElemType data);
fun(ElemType* data);
fun(ElemType data[]);
当然还可以含有多维数组和指针函数这些数据类型,这样在处理const的时候就可以函数合适的地方直接加const就可以了,不用强制转型了~
个人看法某些课本上把
typedef struct Node
{
int data;
char name;
}Node,*P_Node;
这样把Node和*P_Node两个自定义变量写在一起看上去使用很方便,但实际上需要用到const对指针指向的内容进行修饰的时候就麻烦了,所以多写点Node* p_node;这样在某种情况下比P_Node p_node;更适宜(当时我就习惯这样写的,不过后来在用const对指针指向的内容进行修饰的时候就遇到麻烦了)~
当然通常来说能实现基本功能就行,这些可以作为一个参考,还有我说的这些也是自己通过编译器测试发现的,如果发现我说的有疑点并且指正那就更好了~
[此贴子已经被作者于2018-1-11 19:01编辑过]