C/C语言中void和void指针的使用方法
(2007-05-15 22:20:08 )
分类:
C技术
2.void的含义
void字面上为“无类型”,void *为“无类型指针”,void
*可以指任何类型的数据。
void几乎只有“评论”和限制程序的作用。 因为没有人定义过void变量,所以让我们来定义一下:
void a;
此行在编译过程中出错,并显示“illegal use of type”
“语音”。 但是如果void
a的编译毫无疑问,也没有实际意义。
void真正发挥的作用是:
(1)对函数返回的限定
)2)函数参数限定。
众所周知,如果指针p1和p2类型相同,则可以直接在p1和p2之间赋值。如果p1和p2指向不同的数据类型,则必须使用强制类型转换运算符将赋值运算符右侧的指针类型转换为左侧的指针类型。
例如:
浮动* P1;
int *p2;
p1=p2;
其中p1=p2语句发生编译错误,并显示“=' : cannot convert from 'int *”消息
待办事项* '”应改为:
P1=(浮动* ) p2;
然后void
与*不同,任何类型的指针都可以直接赋值,而无需强制类型转换。
void *p1;
int *p2;
p1=p2;
但这意味着,void
*也可以指定给其他类型的指针,而不强制类型转换。 因为“无模”可以包容“有模”,“有模”不能包容“无模”。 道理很简单,可以说“男人女人都是人”,但不能说“人是男人”或“人是女人”。 以下语句的编译错误:
void *p1;
int *p2;
p2=p1;
提示"=' : cannotconvertfrom ' void * ' to ' int * ' "。
3 .使用3.void
void关键字的使用规则如下所示。
如果规则1函数没有返回值,则必须将其声明为void类型
在c语言中,未用返回值类型限定的函数被编译器视为返回值。 但是,很多程序员误认为是void类型。 例如:
添加(int b,int b ) )。
{
返回a b;
}
(intmain(intargc,char* argv[] ) ) ) ) ) ) ) ) ) ) )
{
printf(23=%d )、add )、3 );
}
程序的执行结果为输出:
2=5
这表明不添加返回值说明的函数确实是int函数。
明亮的哈斯基博士《高质量C/C++编程》说:“c语言有严格的类型安全检查,上述情况是不允许的。” 但是,编译器不一定如此。 例如,在Visual中
在C 6.0中,上述add函数的编译没有错误、没有警告地正常工作,因此编译器无法期待进行严格的类型检查。
因此,为了避免混乱,在编写C/C程序时,必须对任何函数无遗漏地指定类型。 如果函数没有返回值,请确保将其声明为void类型。 这既是程序可读性的需要,也是编程规范性的要求。 另外,如果添加void类型声明,则还可以作为代码的“自我注释”。 代码的“自我评论”,即代码可以自己评论自己。
如果规则2函数没有参数,则必须将参数声明为void
用c语言声明这样的函数。
信息(语音) )。
{
返回1;
}
下一次调用不合法。
功能(2;
因为在c中,函数参数为void意味着此函数不接受任何参数。
用涡轮C2.0编译了:
#include 'stdio.h '
fun () )
{
返回1;
}
主() )
{
printf('%d ',fun ) )2);
getchar (;
}
编译正确且输出为1表示,在c语言中,可以向没有参数的函数传递任意类型的参数,但在c编译器中编译相同的代码时会出错。 在c中,不能将参数传递给没有参数的函数。 错误信息“' fun '”
3360 functiondoesnottake 1参数”。
因此,无论是c还是c,如果函数不接受参数,请确保参数为void。
规则3
小心使用void指针类型按照ANSI(American National Standards
Institute)标准,不能对void指针进行算法操作,即下列操作都是不合法的:
void * pvoid;
pvoid++; //ANSI:错误
pvoid += 1; //ANSI:错误
//ANSI标准之所以这样认定,是因为它坚持:进行算法操作的指针必须是确定知道其指向数据类型大小的。
//例如:
int *pint;
pint++; //ANSI:正确
pint++的结果是使其增大sizeof(int)。
但是大名鼎鼎的GNU(GNU's Not Unix的缩写)则不这么认定,它指定void
*的算法操作与char *一致。
因此下列语句在GNU编译器中皆正确:
pvoid++; //GNU:正确
pvoid += 1; //GNU:正确
pvoid++的执行结果是其增大了1。
在实际的程序设计中,为迎合ANSI标准,并提高程序的可移植性,我们可以这样编写实现同样功能的代码:
void * pvoid;
(char *)pvoid++; //ANSI:正确;GNU:正确
(char *)pvoid += 1; //ANSI:错误;GNU:正确
GNU和ANSI还有一些区别,总体而言,GNU较ANSI更“开放”,提供了对更多语法的支持。但是我们在真实设计时,还是应该尽可能地迎合ANSI标准。
规则四 如果函数的参数可以是任意类型指针,那么应声明其参数为void
*
典型的如内存操作函数memcpy和memset的函数原型分别为:
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
这样,任何类型的指针都可以传入memcpy和memset中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型。如果memcpy和memset的参数类型不是void
*,而是char
*,那才叫真的奇怪了!这样的memcpy和memset明显不是一个“纯粹的,脱离低级趣味的”函数!
下面的代码执行正确:
//示例:memset接受任意类型指针
int intarray[100];
memset ( intarray, 0, 100*sizeof(int) ); //将intarray清0
//示例:memcpy接受任意类型指针
int intarray1[100], intarray2[100];
memcpy ( intarray1, intarray2, 100*sizeof(int) );
//将intarray2拷贝给intarray1
有趣的是,memcpy和memset函数返回的也是void
*类型,标准库函数的编写者是多么地富有学问啊!
规则五 void不能代表一个真实的变量
下面代码都企图让void代表一个真实的变量,因此都是错误的代码:
void a; //错误
function(void a); //错误
void体现了一种抽象,这个世界上的变量都是“有类型”的,譬如一个人不是男人就是女人(还有人妖?)。
void的出现只是为了一种抽象的需要,如果你正确地理解了面向对象中“抽象基类”的概念,也很容易理解void数据类型。正如不能给抽象基类定义一个实例,我们也不能定义一个void(让我们类比的称void为“抽象数据类型”)变量。
4.总结
小小的void蕴藏着很丰富的设计哲学,作为一名程序设计人员,对问题进行深一个层次的思考必然使我们受益匪浅。
相关知识:
void指针类型
ANSI
C标准规定用动态存储分配函数时返回void指针,它可以用来指向一个抽象的类型的数据,再将它的值赋给另一指针变量时要进行强制类型转换使之适合于被赋值的变量的类型,如:
char *p1;
void *p2;
...
p1=(char *)p2;
或:p2=(void *)p1;
也可以将一个函数定义为void *类型,如:
void *fun(char ch1,char ch2)
表示函数fun返回的是一个地址,它指向“空类型”,如需要引用此地址,也需要根据情况对之进行类型转换,如:
p1=(char *)fun(ch1,ch2);
分享:
喜欢
0
赠金笔
加载中,请稍候......
评论加载中,请稍候...
发评论
登录名: 密码: 找回密码 注册记住登录状态
昵 称:
评论并转载此博文
发评论
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。