标题:关于使用typedef和const要注意的问题~
取消只看楼主
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
结帖率:99.25%
已结贴  问题点数:100 回复次数:1 
关于使用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编辑过]

搜索更多相关主题的帖子: typedef const void data 函数 
2018-01-11 15:33
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
得分:0 
多谢各位大佬精彩解答学习了~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2018-01-11 19:02



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-484160-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.040881 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved