void
的字面值是“无类型”,void*
则是"无类型指针"。void*
可以指向任何类型的数据。void
几乎只有"注释"和限制程序的作用,因为从来没有人会定义一个void变量。
void a; //编译时提示"illegal use of type 'void'"
void真正发挥的作用在于:
- 对函数返回的限定
- 对函数参数的限定
如果指针p1和p2的类型相同,那么p1和p2之间可互相赋值;如果p1和p2指向不同的数据类型,则必须使用强制类型转换运算符,把赋值运算符右边的指针类型转换为左边指针的类型,然后才可以赋值。如:
float* p1;
int* p2;
p1 = p2; //can't convert from 'int*' to 'float*',必须改为下面这种形式
p1=(float*)p2;
而void*
则不同,任何类型的指针都可以直接赋值给它,无须强制类型转换,例如:
void* p1;
int* p2;
p1 = p2;
但这并不意味void*
也可无须强制转换地赋值给其他类型的指针,这是因为"无类型"可以包含"有类型",而"有类型"不能包容"无类型"
void
和void*
关键字使用规则
-
如果函数没有返回值,那么应声明为void类型。在C语言中,凡不加返回值类型限定的函数,编译器会返回整型值处理,但是许多程序员却误认为其为void类型
例如
add(int a,int b) { return a+b; } int main() { //程序运行结果为2+3=5,这说明不加返回值说明的函数,其返回值的确为int类型 printf("2+3=%d",add(2,3)); }
因此,为避免混乱,对于任何函数都必须指定其返回类型。如果函数没有返回值,一定要声明为void类型。发挥代码的自注释作用。这既是程序良好可读性的需要,也是编程规范性的要求
-
如果函数无参数,那么应声明其参数为
void
。如果在C++语言中声明一个这样的函数int function(void) { // 使用function(2)运行是不合法的,因为在C++中,函数参数为void的意思是这个函数不接受任何参数,但如果在Turbo C2.0中编译则正确 // 说明在C语言中,可以给无参数的函数传送任意类型的参数,但在C++编译器中编译同样的代码则会出错。 // 所以,若函数不接受任何参数,一定要声明为void return 1; }
-
如果函数的参数可以是任意类型的指针,那么应声明其参数为
void*
典型的如内存操作函数:
void* memcpy(void* dest,const void* src,size_t len); void* memset(void* buffer,int c,size_t num);
这样,任何类型的指针都可以传入memcpy和memset中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型
-
void不能代表一个真实的变量
void a; //错误
void体现了一种抽象,这个世界上的变量都是"有类型"的。void的出现只是为了一种抽象的需要,如果你正确地理解了面向对象中"抽象基类"的概念,也很容易理解void数据类型。
sizeof
关键字的使用
-
sizeof
不是一个函数,因为sizeof unary-expression
,sizeof(unary-expression)
和sizeof(type-name)
都合法,而第一种没有括号 -
sizeof
不是一元操作符#include <stdio.h> int main() { int a = 0; printf("%d\n", sizeof(a=3)); printf("%d", a); return 0; }
运行结果为4,0而不是4,3,所以不是一元操作符
这是由于sizeof在编译阶段处理的特性造成的。sizeof不能被编译成机器码,sizeof作用范围内,也就是()里面的内容也不能被编译(a=3语句不能编译成机器码),而是被替换成类型,所以,sizeof不是一元操作符,因为sizeof不支持链式表达式,sizeof作用域范围内的语句不会编译成机器码。更像一个特殊的宏,它在编译阶段求值,例如
cout<<sizeof(int)<<endl; //32位机上输出4 cout<<sizeof(1==2)<<endl; //相当于size(bool),为1
1.sizeof
的用法
sizeof
有两种用法,第一种为针对对象,用法为sizeof(object)
或sizeof object
,第二种为针对类型,用法为sizeof(typename)
,例如
int i = 2;
cout<<sizeof(i)<<endl; //sizeof(object)的用法,合理
cout<<sizeof i<<endl; //sizeof object的用法,合理
cout<<sizeof 2<<endl; //2被解析成int类型的object,sizeof object的用法,合理
cout<<sizeof(int)<<endl; //sizeof(typename)的用法,合理
cout<<sizeof int<<endl; //错误,对于操作符,一定要加(),无论是对对象还是对类型取值,sizeof写成sizeof这种函数形式永远是正确的
2.基本数据类型的sizeof
函数类型和指针类型都属于指针的范畴,指针主要用于存储地址,在32位系统下,任何类型的指针其所占用的内存大小均为4字节;而函数类型比较特别,它以其返回类型作为自身类型进行sizeof取值。无论指针是什么类型,只要是指针,sizeof运算结果都是4
函数类型以其返回值的类型作为自身类型。注意不能对返回void的函数进行sizeof取值,也不能对函数指针进行sizeof取值
int f1()
{
return 0;
}
double f2()
{
return 0;
}
void f2()
{
return 0;
}
cout<<sizeof(f1())<<endl; //f1()返回值为int,因此被认为是int
cout<<sizeof(f2())<<endl; //f2()返回值为double,因此被认为是double
cout<<sizeof(f3())<<endl; //错误,无法对void类型使用sizeof
cout<<sizeof(f1)<<endl; //错误,无法对函数指针使用sizeof
下面是数组的sizeof
char a[] = "abvdef";
char b[] = {'a','b','c','d','e','f'};
int c[20] = {3,4}
char d[2][3]={"aa","bb"};
cout<<sizeof(a)<<endl; //输出7,表示字符串
cout<<sizeof(b)<<endl; //输出6,仅表示字符数组
cout<<sizeof(c)<<endl; //输出80
cout<<sizeof(d)<<endl; //输出6
cout<<sizeof(*a)<<endl; //输出1
cout<<sizeof(*b)<<endl; //输出1
cout<<sizeof(*c)<<endl; //输出4
cout<<sizeof(*d)<<endl; //输出3
如果字符数组表示字符串的话,数组末尾自动插入的\0
,在sizeof时不能遗漏,所以数组a的大小在定义时未指定,编译时给它分配的空间是按照初始化的值确定的,也就是7。
c是多维数组,占用的空间大小是各维数的乘积,也就是6,可以看出,数组的大小就是它在编译时被分配的空间,也就是各维数的乘积,也就是6。可以看出数组的大小就是它在编译时被分配的空间,也就是各维数的乘积*数组元素的大小
。对应二维数组d,*d
等价于d[0]
(d[0]是一维数组长度为3),所以sizeof(*d)等于3
C语言中多维数组的实现是通过一维数组实现的,也就是说对于多维数组,你所操作的数组元素有可能本身就是一个数组。这是应该引起注意的。数组的大小是各维数的乘积*数组元素的大小
向函数开通传递数组,数组将会退化为指针,失去了原有数组的特性
int GetStrLength(char str[])
{
return sizeof(str);
}
int main()
{
char szStr[] = "abcdef";
cout<<"sizeof(szStr[])="<<GetStrLength()<<endl;
//输出sizeof(szStr[])=4
}
sizeof(void*)
sizeof(void *)
获取指针类型的大小。根据不同的平台,得到结果会不同。
- Win32 平台结果是 4
- X64平台结果是 8
原因就是指针存放的是内存地址,所以Win32 索引32位地址(4字节),X64索引64位地址(8字节)