void指针及其应用,C语言void指针及使用注意事项详解
void *p1; int *p2; p1 = p2;
虽然如此,但这并不意味着可以无需任何强制类型转换就将 void 指针直接赋给其他类型的指针,因为 空类型 可以包容 有类型 ,而 有类型 则不能包容 空类型 。正如我们可以说 男人和女人都是人 ,但不能说 人是男人 或者 人是女人 一样。因此,下面的示例代码将编译出错,如果在 VC++2010 中,将提示 a value of type void* cannot be assigned to an entity of type int* 的错误信息。
void *p1; int *p2; p2 = p1;
由此可见,要将 void 指针赋值给其他类型的指针,必须进行强制类型转换。如下面的示例代码所示:
void *p1; int *p2; p2 = (int*)p1;避免对void指针进行算术操作
ANSI C 标准规定,进行算法操作的指针必须确定知道其指向数据类型大小,也就是说必须知道内存目的地址的确切值。如下面的示例代码所示:
char a[20]= qwertyuiopasdfghjkl int *p=(int *)a; printf( %s , p);
在上面的示例代码中,指针变量 p 的类型是 int* ,指向的类型是 int,被初始化为指向整型变量 a。
在执行语句 p++ 时,编译器是这样处理的:把指针 p 的值加上了 sizeof(int) (由于在 32 位系统中,int 占 4 字节,所以这里是被加上了 4),即 p 所指向的地址由原来的变量 a 的地址向高地址方向增加了 4 字节。但又由于 char 类型的长度是一个字节,所以语句 printf( %s ,p) 将输出 tyuiopasdfghjkl 。
而对于 void 指针,编译器并不知道所指对象的大小,所以对 void 指针进行算术操作都是不合法的,如下面的示例代码所示:
void * p; p++; // ANSI:错误 p+= 1; // ANSI:错误
上面的代码在 VC++2010 中将提示 expression must be a pointer to a complete object type 的错误信息。
但值得注意的是,GNU 则不这么认为,它指定 void* 的算法操作与 char* 一致。因此下列语句在 GNU 编译器中都是正确的:
void * p; p++; // GUN:正确 p+=1; // GUN:正确
下面的示例代码演示了在 GCC 中执行对 void 指针的自增操作:
#include stdio.h int main(void) void * p= ILoveC p++; printf( %s/n , p); }
运行结果为:
LoveC
由此可见,GNU 和 ANSI 还存在着一些区别,相比之下,GNU 较 ANSI 更 开放 ,提供了对更多语法的支持。但是在真实的设计环境中,还是应该尽可能符合 ANSI 标准,尽量避免对 void 指针进行算术操作。
如果函数的参数可以是任意类型指针,应该将其参数声明为 void*前面提到,void 指针可以指向任意类型的数据,同时任何类型的指针都可以直接赋值给 void 指针,而无需进行其他相关的强制类型转换。因此,在编程中,如果函数的参数可以是任意类型指针,那么应该使用 void 指针作为函数的形参,这样函数就可以接受任意数据类型的指针作为参数。
比较典型的函数有内存操作函数 memcpy 和 memset,如下面的代码所示:
void *memset(void *buffer, int b, size_t size) assert(buffer!=NULL); char* retAddr = (char*)buffer; while (size-- 0) *(retAddr++) = (char)b; return retAddr; void *memcpy (void *dst, const void *src, size_t size) assert((dst!=NULL) (src!=NULL)); char *temp_dest = (char *)dst; char *temp_src = (char *)src; char* retAddr = temp_dest; size_t i = 0; /* 解决数据区重叠问题*/ if ((retAddr temp_src) (retAddr (temp_src+size))) for (i=size-1; i i--) *(temp_dest++) = *(temp_src++); else for (i=0; i size; i++) *(temp_dest++) = *(temp_src++); *(retAddr+size)= /0 return retAddr; }
这样,任何类型的指针都可以传入 memcpy 函数和 memset 函数中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型。memcpy 函数的调用示例如下面的代码所示:
char buf[]= abcdefg // buf+2(从c开始,长度3个,即cde) memcpy(buf, buf+2 ,3); printf( %s/n , buf);
或者进行如下形式的调用:
int dst[100]; int src[100]; memcpy(dst, src, 100*sizeof(int));
因为参数类型是 void*,所以上面的调用都是正确的。现在假设 memcpy 函数的参数类型不是 void*,而是 char*,如下面的代码所示:
char *memcpy(char* dst, const char* src, size_t size) assert((dst !=NULL) (src != NULL)); char *retAddr = dst; size_t i = 0; if ((retAddr src) (retAddr (src+size))) for (i=size-1; i i--) *(dst++)= *(src++); else for (i=0; i size; i++) *(dst++) = *(src++); *(retAddr+size)= /0 return retAddr; }
现在继续执行如下形式的调用:
int dst[100]; int src[100]; memcpy(dst, src, 100*sizeof(int));
由于类型不匹配,编译器就会报错,如图 1 所示。
由此可见,这样的函数同时也失去了通用性。
21155.html
cGCC相关文章
- kmp优化模板----------------------C语言——菜鸟级
- C语言逗号运算符(,)
- C语言中什么是常量表达式_c语言整型表达式
- 【C语言应用】如何用C代码生成一维码?
- 相见恨晚!C语言的驱动法编程详细解析(超多代码案例)
- Linux系统中C语言函数的应用(linux的c函数)
- MySQL连接之C语言实现(c如何与mysql连接)
- 的应用Linux系统中C语言的强大威力.(linux中c语言)
- 编程开发Linux应用的C语言图形编程实践(linuxc图形)
- 在Linux系统中使用C语言编辑器(linux下c编辑器)
- 学习Oracle C语言:一种崭新的操作体验(oraclec语言操作)
- C语言在Linux环境下的应用(linux c 后缀名)
- 让嵌入式Linux应用跑起来——C语言编程实战(嵌入式linux c程序)
- MySQL C语言API应用注意事项(mysqlc语言api)
- C语言编程开发之MySQL数据库应用(c 与mysql如何使用)
- C语言MySQL类应用之旅(c mysql类使用)
- C语言与MySQL短连接应用实践(c mysql短连接)
- MySQL在创建复杂C语言应用程序方面的威力(c mysql 应用程序)
- C语言与MySQL联手打造实体框架(C mysql 实体框架)
- 使用C语言与MySQL删除数据表中的行(c mysql 删除行)
- 数据库C语言实现从Oracle数据库导出功能(c语言导出oracle)
- MySQL与C语言协同构建健壮连接体系(c mysql两个连接)
- C语言与Oracle数据库的新增应用(c oracle 新增)
- 利用C语言连接Oracle数据库实现中文化应用(c oracle 中文)
- 混合开发助力企业信息化C语言PHP和MySQL联动提升系统性能(c php mysql)
- 用MySQL和C语言编程,快速构建高效数据库应用(mysql_,c语言编程)
- 使用C语言实现CRC校验的方法
- C语言中函数与指针的应用总结
- C语言实现排序算法之归并排序详解
- C语言实现的bitmap位图代码分享