| 网站首页 | 业界新闻 | 群组 | 交易 | 人才 | 下载频道 | 博客 | 代码贴 | 编程论坛
共有 475 人关注过本帖
标题:关于使用typedef和const要注意的问题~
只看楼主 加入收藏
九转星河
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:长长久久
等 级:版主
威 望:51
帖 子:4979
专家分:13965
注 册:2016-10-22
结帖率:100%
  已结贴   问题点数:100  回复次数:4   
关于使用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编辑过]

2018-01-11 15:33
wp231957
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:神界
等 级:贵宾
威 望:367
帖 子:12742
专家分:49749
注 册:2012-10-18
  得分:34 
我觉得const在c++里地位挺高的 在c里并不被广泛使用

DO IT YOURSELF !
2018-01-11 15:51
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:260
帖 子:5801
专家分:33080
注 册:2011-1-18
  得分:34 
int const * const a = 0; 或 const int * const a = 0;
第一个 const 修饰 *a,因为它之后是 *a
第二个 const 修饰 a,因为它之后是 a

const int* p2 = NULL; 中 const int 是个整体
而 typedef int* intptr; const intptr p = NULL; 中 int* 是个整体。
所以 const intptr p = NULL 等价于 int* const p = NULL,即 p 只读,而 *p 不是。


2018-01-11 15:56
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:157
帖 子:6134
专家分:26816
注 册:2014-5-20
  得分:34 
const修饰指针时:
const int *p; // p 可变,p 指向的对象不可变
int const *p; // p 可变,p 指向的对象不可变
int *const p; // p不可变,p 指向的对象可变
const int *const p; //指针 p 和 p 指向的对象都不可变

先忽略类型名(编译器解析的时候也是忽略类型名)
看 const 离哪个近。“近水楼台先得月”,离谁近就修饰谁。
const int *p; //const 修饰*p, p 是指针,*p 是指针指向的对象,不可变
int const *p; //const 修饰*p, p 是指针,*p 是指针指向的对象,不可变
int *const p; //const 修饰 p,p 不可变,p 指向的对象可变
const int *const p; //前一个 const 修饰*p, 后一个 const 修饰 p,指针 p 和 p 指向的对象都不可变

2018-01-11 16:09
九转星河
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:长长久久
等 级:版主
威 望:51
帖 子:4979
专家分:13965
注 册:2016-10-22
  得分:0 
多谢各位大佬精彩解答学习了~

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







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

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