void*
c
void void_pointer()
{
int i = 5;
void* pv = &i;
int* pi = pv;
printf("sizeof(void) = %ld\n", sizeof(void));
printf("pv = %p, pi = %p, *pi = %d\n", pv, pi, *pi);
pv++;
printf("pv = %p\n", pv);
pv += 5;
printf("pv = %p\n", pv);
*pv;
//i = *pv;
}
output:
sizeof(void) = 1
pv = 0x7fff5fbff834, pi = 0x7fff5fbff834, *pi = 5
pv = 0x7fff5fbff835
pv = 0x7fff5fbff83a
总结:
- void指针基础类型为void,而void类型字长为1,因此void指针单位偏移地址为1,因此void指针支持算术运算
- 支持对void*指针使用*运算(不支持直接使用void类型,因此没有void类型对象)
- 支持void*类型指针转其他类型指针
c++
void void_pointer()
{
int i = 5;
void* pv = &i;
//int* pi = pv;
//printf("sizeof(void) = %ld\n", sizeof(void));
//printf("pv = %p, pi = %p, *pi = %d\n", pv, pi, *pi);
//pv++;
printf("pv = %p\n", pv);
//pv += 5;
printf("pv = %p\n", pv);
//*pv;
//i = *pv;
}
总结:
- void指针基础类型为void,而void类型字长未定义,因此void指针单位偏移地址未定义,因此void指针不支持算术运算
- 不支持对void*指针使用*运算,因为void字长未定义
- 不支持void*类型指针转其他类型指针
函数指针
c
c不支持函数重载,因此函数名唯一确定函数,因此如果函数声明omit形参,编译时函数调用会ignore形参检查(形参个数和类型),如果函数运行异常,运行期才能发现,但如果没有omit形参,编译时函数调用会做形参检查(形参个数和类型)
假如feed.c中定义如下函数
void feed(int rice, int meat)
{
printf("feed rice %d and meat %d\n", rice, meat);
}
在main.c中进行如下函数调用
void feed();
void call_feed()
{
feed();
feed(5);
feed(5, 8);
feed(5, 8, 58);
}
output:
feed rice 1 and meat 1606416504
feed rice 5 and meat 73832
feed rice 5 and meat 8
feed rice 5 and meat 8
注:feed(),feed(5)实参缺失,函数运行异常,feed(5, 8, 58)传递了多余实参
因为c不支持函数重载,feed()调用link时search _sub_feed_(不包含形参)目标代码入口,而void feed(int rice, int meat)函数定义在目标代码中入口地址为_sub_feed_(不包含形参),因此link时能search到,正确link
函数这个特性相应扩展到了函数指针类型,如果函数指针类型omit形参,编译时函数指针类型ignore形参检查(形参个数和类型),如果函数指针类型运行异常,运行期才能发现,但如果没有omit形参,编译时函数指针类型会做形参检查(形参个数和类型),因此omit形参的函数指针类型(无参函数指针类型)与没有omit形参的函数指针类型(含参函数指针类型)可相互转换(函数返回类型必须一致)
void feed0()
{
printf("feed none\n");
}
void feed1(int rice)
{
printf("feed rice %d\n", rice);
}
void feed2(int rice, int meat)
{
printf("feed rice %d and meat %d\n", rice, meat);
}
void feed3(int rice, int meat, int fruit)
{
printf("feed rice %d and meat %d and fruit %d\n", rice, meat, fruit);
}
typedef void (*PFeed0)();
typedef void (*PFeed1)(int);
typedef void (*PFeed2)(int, int);
typedef void (*PFeed3)(int, int, int);
void fun_pointer()
{
PFeed0 pfeed0 = feed0;
PFeed1 pfeed1 = feed1;
PFeed2 pfeed2 = feed2;
PFeed3 pfeed3 = feed3;
pfeed0 = feed1;
pfeed0 = feed2;
pfeed0 = feed3;
pfeed0();
pfeed0(5);
pfeed0(5, 8);
pfeed0(5, 8, 58);
pfeed1 = feed0;
pfeed2 = feed0;
pfeed3 = feed0;
//pfeed1();
pfeed1(5);
//pfeed2();
pfeed2(5, 8);
//pfeed3();
pfeed3(5, 8, 58);
//pfeed1 = feed2;
//pfeed2 = feed1;
//pfeed1 = feed3;
//pfeed3 = feed1;
//pfeed2 = feed3;
//pfeed3 = feed2;
}
output:
feed rice 0 and meat 0 and fruit 0
feed rice 5 and meat 0 and fruit 0
feed rice 5 and meat 8 and fruit 0
feed rice 5 and meat 8 and fruit 58
feed none
feed none
feed none
注:通过omit形参的函数指针类型(无参函数指针类型)调用函数时,ignore形参检查(形参个数和类型)
c++
c++支持函数重载,因此函数名+形参(形参个数和类型)唯一确定函数,omit形参的函数声明仅仅表示无参函数声明,没有多余其他含义,编译时函数调用无论如何都会做形参检查(形参个数和类型)
假如feed.cpp中定义如下函数
void feed(int rice, int meat)
{
printf("feed rice %d and meat %d\n", rice, meat);
}
在main.cpp中进行如下函数调用
void feed();
void call_feed()
{
feed();
//feed(5);
//feed(5, 8);
//feed(5, 8, 58);
}
注:编译时,feed(5),feed(5, 8),feed(5, 8, 58)与函数声明void feed()形参不匹配,而feed()尽管与函数声明void feed()匹配,但link error
因为c++支持函数重载,feed()调用link时search _sub_feed_目标代码入口(包含形参,表示无参),而void feed(int rice, int meat)函数定义在目标代码中入口地址为_sub_feed_int_int_(包含形参,两个形参int,int),因此link时search不到,link error
函数这个特性相应扩展到了函数指针类型,因此c++支持函数重载,因此omit形参的函数指针类型仅仅表示无参函数指针类型,没有多余其他含义,编译时函数指针类型无论如何都会做形参检查(形参个数和类型),因此omit形参的函数指针类型(无参函数指针类型)与没有omit形参的函数指针类型(含参函数指针类型)不可相互转换(函数返回类型必须一致)
void feed0()
{
printf("feed none\n");
}
void feed1(int rice)
{
printf("feed rice %d\n", rice);
}
void feed2(int rice, int meat)
{
printf("feed rice %d and meat %d\n", rice, meat);
}
void feed3(int rice, int meat, int fruit)
{
printf("feed rice %d and meat %d and fruit %d\n", rice, meat, fruit);
}
typedef void (*PFeed0)();
typedef void (*PFeed1)(int);
typedef void (*PFeed2)(int, int);
typedef void (*PFeed3)(int, int, int);
void fun_pointer()
{
PFeed0 pfeed0 = feed0;
PFeed1 pfeed1 = feed1;
PFeed2 pfeed2 = feed2;
PFeed3 pfeed3 = feed3;
//pfeed0 = feed1;
//pfeed0 = feed2;
//pfeed0 = feed3;
pfeed0();
//pfeed0(5);
//pfeed0(5, 8);
//pfeed0(5, 8, 58);
//pfeed1 = feed0;
//pfeed2 = feed0;
//pfeed3 = feed0;
//pfeed1();
pfeed1(5);
//pfeed2();
pfeed2(5, 8);
//pfeed3();
pfeed3(5, 8, 58);
//pfeed1 = feed2;
//pfeed2 = feed1;
//pfeed1 = feed3;
//pfeed3 = feed1;
//pfeed2 = feed3;
//pfeed3 = feed2;
}
output:
feed none
feed rice 5
feed rice 5 and meat 8
feed rice 5 and meat 8 and fruit 58