指针本质论

指针有两个属性:指向变量/对象的地址和长度。

但是指针只存储地址,长度则取决于指针的类型,
编译器根据指针的类型从指针指向的地址向后寻址,
指针类型不同则寻址范围也不同,比如:
int*从指定地址向后寻找4字节作为变量的存储单元,
double*从指定地址向后寻找8字节作为变量的存储单元 ,

1.void指针是一种特别的指针
   void *vp
  //说它特别是因为它没有类型
  //或者说这个类型不能判断出指向对象的长度

2.任何指针都可以赋值给void指针
  type *p;
  vp=p;
  //不需转换
  //只获得变量/对象地址而不获得大小

3.void指针赋值给其他类型的指针时都要进行转换
   type *p=(type*)vp;
   //转换类型也就是获得指向变量/对象大小
转:http://icoding.spaces.live.com/blog/cns!209684E38D520BA6!130.entry

4.void指针不能复引用
  *vp//错误
  因为void指针只知道,指向变量/对象的起始地址
  而不知道指向变量/对象的大小(占几个字节)所以无法正确引用

5.ANSI下void指针不能参与指针运算,除非进行转换,GNU允许
   (type*)vp++;
  //vp==vp+sizeof(type)

深度详解

如果指针p1和p2的类型相同,那么我们能直接在p1和p2间互相赋值;

如果p1和p2指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的指针类型转换为左边指针的类型。

例如:

float *p1;

int *p2;

p1 = p2;

其中p1 = p2语句会编译出错,提示“’=’ : cannot convert from ’int *’ to ’float *’”,必须改为:

p1 = (float *)p2;

而void *则不同,所有类型的指针都能直接赋值给他,无需进行强制类型转换:

void *p1;
int *p2;
p1 = p2;

void *必须强制类型转换才能赋给其他类型的指针。因为“无类型”能包容“有类型”,而“有类型”则不能包容“无类型”。


1.void

《C程序设计语言(第2版新版)》

2.void*

《C程序设计语言(第2版新版)》

《C语言入门经典(第四版)》

《21天学通C语言(第6版)》

如果函数的参数能是任意类型指针,那么应声明其参数为void *。

3.指针转换

《C程序设计语言(第2版新版)》

4.指针运算

《21天学通C语言(第6版)》

例子:直接给void*指针运算会报错--“void*:未知的大小”

可以将空指针强制转换即可:       (unsigned char*)k=(unsigned char*)k+1;

按照ANSI(American National Standards Institute)标准,不能对void指针进行算法操作,即下列操作都是不合法的:

void * pvoid;
pvoid++;  //ANSI:错误
pvoid += 1; //ANSI:错误

ANSI标准之所以这样认定,是因为他坚持:进行算法操作的指针必须是确定知道其指向数据类型大小的。例如:

int *pint;
pint++; //ANSI:正确
pint++的结果是使其增大sizeof(int)。

不过GNU则指定void *的算法操作和char *一致。GNU下的void *p++相当于char *p++ 也就是移动一个字节。

因此下列语句在GNU编译器中皆正确:

pvoid++; //GNU:正确
pvoid += 1; //GNU:正确

pvoid++的执行结果是其增大了1。

在实际的程式设计中,为迎合ANSI标准,并提高程式的可移植性,我们能这样编写实现同样功能的代码:

void * pvoid;
(char *)pvoid ++; //ANSI:正确;GNU:正确
(char *)pvoid += 1; //ANSI:错误;GNU:正确

[JOEY 评:此处尚有疑问,(char *) pvoid ++,VS2005编译无法通过,提示:“void *”:未知的大小。]

GNU和ANSI更有一些差别,总体而言,GNU较ANSI更“开放”,提供了对更多语法的支持。不过我们在真实设计时,还是应该尽可能地迎合ANSI标准。

5.Nginx源码中的用法

声明内存池的结构,是使用u_char *定义last和end指针

typedef struct {u_char *last;u_char *end;ngx_pool_t *next;
}ngx_pool_data_t;

初始化

ngx_pool_t *ngx_create_pool(size_t size)
{ngx_pool_t *p;p=(ngx_pool_t*)malloc(size);p->d.last=(u_char *)p+sizeof(ngx_pool_t);p->d.end=(u_char *)p+size;size = size - sizeof(ngx_pool_t);p->max =size;p->current = p;return p;
}

内存分配

void *palloc(ngx_pool_t *pool,size_t size)
{u_char      *m;ngx_pool_t  *p;if (size <= pool->max){p = pool->current;do{m = p->d.last;if ((size_t) (p->d.end - m) >= size) {(u_char *)p->d.last+=size;return m;}p = p->d.next;}while(p);

以上的正常的使用没问题的。

其实可以将u_char *定义last指针改为void*指针,但是如果在指针运算使用的时候不进行强制转换会报错。这个和前面的void * k直接运算是一样的问题。

代码做下修改即可:

do{m = p->d.last;if ((size_t) (p->d.end - m) >= size) {(u_char *)p->d.last+=size;return m;}p = p->d.next;}while(p);

注意:void*空指针运算这个问题在Linux下用gcc编译不报错

下图是Nginx内存池图:

参考:指针的本质1--u_char*指针在Nginx源码中的应用及原因

指针的本质2-void和void*及其应用在nginx中的应用相关推荐

  1. 关于空指针(指针指向为NULL)和void类型的指针的理解

    正在学C,书上老说空指针,或者说void指针,对于我这样的生手来说,理解非常容易造成混淆,因为void这个单词的意思也是空,到底空指针的意思是指指向地址为空的类型呢,还是指void类型的指针呢 (1) ...

  2. [转]C/C++语言void及void指针深层探索

    1.概述 许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误.本文将对void关键字的深刻含义进行解说,并详述void及void指针类型的使用方法与技巧. 2 ...

  3. C/C++语言void及void指针深层探索 .

    1.概述 许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误.本文将对void关键字的深刻含义进行解说,并详述void及void指针类型的使用方法与技巧. 2 ...

  4. 对函数指针与typedef的理解:typedef void (*sighandler_t)(int)

    文章目录 缘由 解释函数指针int (\*f)(int*); 解释typedef void(*sighandler_t)(int) 缘由 2021年9月22日在刷CS:APP的时候,邂逅了一种函数指针 ...

  5. C语言 void和void *(无类型指针)

    void 关键字 void的字面意思是"无类型",void *则为"无类型指针",void *可以指向任何类型的数据. void几乎只有"注释&quo ...

  6. C++中void和void*指针的含义 (指针类型的含义)

    转载自:http://blog.csdn.net/lee_shuai 指针有两个属性:指向变量/对象的地址和长度,但是指针只存储地址,长度则取决于指针的类型:编译器根据指针的类型从指针指向的地址向后寻 ...

  7. 【转】void及void指针的深刻解析

    void的含义 void即"无类型" ,void*则为"无类型指针",可以指向任何数据类型,所以又叫做"通用指针". void指针使用规范 ...

  8. static关键字 void和void指针 函数指针

    static关键字 1.作用于变量:    用static声明局部变量-------局部变量指在代码块{}内部定义的变量,只在代码块内部有效(作用域),其缺省的存储方式是自动变量或说是动态存储的,即指 ...

  9. C/C++语言void及void指针深层探索

    1.概述 许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误.本文将对void关键字的深刻含义进行解说,并详述void及void指针类型的使用方法与技巧. 2 ...

最新文章

  1. 智能连接:5G、AI和IoT的组合如何改变美洲
  2. java四行代码实现图片下载
  3. 一家创业公司,如何服务好数百企业?
  4. 移动web端页面设置的特殊样式列举
  5. boost::math::chebyshev_transform用法的测试程序
  6. python中的property
  7. 基于Xml 的IOC 容器-载入<bean>元素
  8. svn搭建本地服务端
  9. linux 网络路径中网络协议栈有几种,linux网络路径中网络协议栈有几种
  10. DW ——随机抽号(七位)(JavaScript)
  11. 最好的移动安全计划:先检查风险 再对症下药
  12. 并发编程 07—— 任务取消
  13. Android系统在超级终端下必会的命令大全(adb shell命令大全)
  14. 阈值分割python实现
  15. 如何自定义快捷方式图标为自己的图片(保姆级教程)
  16. 苹果官方mfi认证名单_苹果入驻抖音,完成官方认证
  17. 【CSP-S2019模拟】09.25比赛总结
  18. java基础(三):java面向对象OOP
  19. 开箱即用的Vue 框架
  20. 1024程序员节来喽

热门文章

  1. C++中一些你不知道的冷知识
  2. C++:随笔3--复杂的数据结构
  3. 红外遥感设计报告论文+电路原理图
  4. kali2020安装中文输入法(切换中文输入法)
  5. php把excel变成数组,PHP excel读取excel文件转换为数组
  6. Marvelous Designer衣袖设计教程
  7. 设计模式 之美 --- 初篇
  8. ubuntu自定义命令
  9. Python并行编程(八):with语法
  10. 下面为初学者分享一下SQL 数据库学习资料