void的字面值是“无类型”,void*则是"无类型指针"。void*可以指向任何类型的数据。void几乎只有"注释"和限制程序的作用,因为从来没有人会定义一个void变量。

void a;    //编译时提示"illegaluseoftype'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关键字使用规则

1.如果函数没有返回值,那么应声明为void类型。在C语言中,凡不加返回值类型限定的函数,就会编译器作为返回整型值处理,但是许多程序员却误认为其为void类型

例如

add(int a,int b)              int main()

{                     {

  return a+b;                printf("2+3=%d",add(2,3));

}                     }  //程序运行结果为2+3=5,这说明不加返回值说明的函数,其返回值的确为int类型

因此,为避免混乱,对于任何函数都必须指定其返回类型。如果函数没有返回值,一定要声明为void类型。发挥代码的自注释作用。这既是程序良好可读性的需要,也是编程规范性的要求

2.如果函数无参数,那么应声明其参数为void.如果在C++语言中声明一个这样的函数

int function(void)      //则进行function(2)是不合法的,因为在C++中,函数参数为void的意思是这个函数不接受任何参数,但如果在Turbo C2.0中编译则正确        

{              //说明在C语言中,可以给无参数的函数传送任意类型的参数,但在C++编译器中编译同样的代码则会出错。所以,若函数不接受任何参数,一定要声明为void

  return 1;

}

3.如果函数的参数可以是任意类型的指针,那么应声明其参数为void*

典型的如内存操作函数:

void* memcpy(void* dest,const void* src,size_t len);

void* memset(void* buffer,int c,size_t num);

这样,任何类型的指针都可以传入memcpy和memset中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型

4.void不能代表一个真实的变量

void a      //错误

void体现了一种抽象,这个世界上的变量都是"有类型"的。void的出现只是为了一种抽象的需要,如果你正确地理解了面向对象中"抽象基类"的概念,也很容易理解void数据类型。

二.sizeof

sizeof不是一个函数,因为sizeof unary-expression,sizeof(unary-expression)和sizeof(type-name)都合法,而第一种没有括号

sizeof不是一元操作符,int a = 0;cout<<sizeof(a=3)<<endl;cout<<a<<endl;  运行结果为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()          double f2()        void f2()

{             {              {

  return 0;          return 0;        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[])            int main()

{                         {

  return sizeof(str);                 char szStr[] = "abcdef";

}                           cout<<"sizeof(szStr[])="<<GetStrLength()<<endl;

                          }        //输出sizeof(szStr[])=4

struct的sizeof为CPU对齐问题

对一个空struct结构体取sizeof运算,运算结果为1而不是0。这是编译器为了保证此空struct存在而专门分配的这一字节,如果存在结构体嵌套,无论外层还是内层均需采用内存对齐

class数据结构的sizeof问题

1.不含继承和static成员变量的类

此种情况下,类类型和struct类型对象大小的处理方式相同,只需考虑对齐方式即可,例如

class CA

{

};

class CB

{

  private:

    int m_nValue;

    double m_dValue;

  public:

    int GetInt() {return m_nValue;}

    double GetDouble(){return m_dValue;}

};

cout<<"sizeof(CA)="<<sizeof(CA)<<endl;

cout<<"sizeof(CB)="<<sizeof(CB)<<endl;

运行结果如下:

sizeof(CA) = 1    sizeof(CB) = 16

总结:

不含继承和static成员变量的类,类对象大小计算遵循下面的准则

和struct复合类型一样,空的class同样也占用1字节

class类型和struct一样采用对齐来计算对象的大小

计算类对象的大小时,类的成员函数不占用对象空间,只需考虑类中数据成员的大小即可。因为它们为所有的类对象共享,存储于代码段中

2.包含继承和static成员变量的类

在单继承情况下,只要class中存在virtual函数,在编译时编译器就会自动插入一个指向虚函数表的指针vptr(大小为4字节)。不同的编译器,vptr插入的位置可能不同,VC编译器插入vptr的位置一般从数据成员开始。而static成员是分配在全局区为类的所有对象共享(VC编译器可能为了方便将其放入文字常量表),sizeof时不应计入static成员。

class CBase

{

  public:

    virtual void foo(){};

  private:

    int m_nValue1;

}

class CStaticClass

{

  private:

    static double m_dValue;

};

class CDrivedA:public CBase

{

  private:

    virtual void foo(){}

  private: 

    int m_nValue2;

};

int main()

{

  cout<<"sizeof(CStaticClass)="<<sizeof(CStaticClass)<<endl;

  cout<<"sizeof(CBase)="<<sizeof(CStaticClass)<<endl;

  cout<<"sizeof(CDrived)="<<sizeof(CStaticClass)<<endl;

  return 0;

}

执行结果为:

sizeof(CStaticClass)=1

sizeof(CBase)=8

sizeof(CDrived)=12

对于类CStaticClass,虽然包含了一个static double类型的成员变量,但是CStaticClass大小却是1,所以可以看出static成员变量不占用对象大小。对于CBase类只包含一个成员变量,理论大小应该是4,而实际是8,所以class中存在virtual函数,编译器就会自动插入一个指向虚函数表的指针vptr(大小为4字节)

影响类大小的因素总结如下:

1.类的非static类型数据成员

2.类是否存在virtual成员函数

3.当前编译所采用的对齐方式

深刻理解void,void*和sizeof关键字的更多相关文章

  1. C++ 类的多态一(virtual关键字--构造函数深刻理解)

    //virtual关键字--构造函数深刻理解 #include<iostream> using namespace std; /* C语言编译器,c++编译器全部是静态链编,就是一段一段代 ...

  2. 如何理解typedef void (*pfun)(void)

    问题: 在刚接触typedef void (*pfun)(void) 这个结构的时候,存在疑惑,为什么typedef后只有一"块"东西,而不是两"块"东西呢?那 ...

  3. 简述static关键字、void与void *(void指针)、函数指针

    static关键字1.修饰局部变量,延长局部变量的生命周期.使变量成为静态局部变量,在编译时就为变量分配内存,直到程序退出才释放存储单元.2.修饰全局变量,限制全局变量的使用范围为本文件中.全局变量默 ...

  4. 函数指针-如何理解typedef void (*pfun)(void)

    问题: 在刚接触typedef void (*pfun)(void) 这个结构的时候,存在疑惑,为什么typedef后只有一"块"东西,而不是两"块"东西呢?那 ...

  5. 【转载】理解C语言中的关键字extern

    原文:理解C语言中的关键字extern 最近写了一段C程序,编译时出现变量重复定义的错误,自己查看没发现错误.使用Google发现,自己对extern理解不透彻,我搜到了这篇文章,写得不错.我拙劣的翻 ...

  6. 深刻理解Java中final的作用(一):从final的作用剖析String被设计成不可变类的深层原因

    声明:本博客为原创博客,未经同意,不得转载!小伙伴们假设是在别的地方看到的话,建议还是来csdn上看吧(原文链接为http://blog.csdn.net/bettarwang/article/det ...

  7. 深刻理解iosBlock

    深刻理解iosBlock ///一个控制器里的方法 - (void)setRefreshHeader { ACWeakSelf(self); self.tableView.mj_header = [M ...

  8. C语言学习笔记--enum和sizeof关键字

    1.enum关键字 C语言中enum关键字用来定义枚举类型 (1)enum 是 C 语言中的一种自定义类型(2)enum 值是可以根据需要自定义的的整型值(3)第一个定义的 enum 值默认为 0 ( ...

  9. 深刻理解Java中的String、StringBuffer和StringBuilder的差别

    声明:本博客为原创博客,未经同意.不得转载!小伙伴们假设是在别的地方看到的话,建议还是来csdn上看吧(链接为http://blog.csdn.net/bettarwang/article/detai ...

随机推荐

  1. 二道shell面试题

    1.按照给出的运行结果,编写一个名为xunhuan 的shell过程(用循环语句). 0 10 210 3210 43210 543210 6543210 76543210 876543210 2.编 ...

  2. mysql 语句练习

    一.            设有一数据库,包括四个表:学生表(Student).课程表(Course).成绩表(Score)以及教师信息表(Teacher).四个表的结构分别如表1-1的表(一)~表( ...

  3. 数学题(找规律)-hdu-4371-Minimum palindrome

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4731 题目大意: 给一个n表示有n种字母(全部小写),给一个m,求一个由不超过n种字母组成的m个小写 ...

  4. asp.net DropDownList实现ToolTip功能

    在绑定DropDownList控件时,可能出现绑定显示的文本过长以至于超过控件长度的内容看不到,这时候就需要使用ToolTip完成其功能,即鼠标放到相应选项后就可显示其完成内容. 首先,在页面引入jQ ...

  5. 【Winform开发2048小游戏】

    先来看一下界面: 游戏帮助类 class GameCore { //游戏地图 private int[,] map = new int[4, 4]; //合并时用到的临时数组 private int[ ...

  6. 2.1确定一个char包含何种字符

    知识点: 1.char.IsControl 2.char.IsPunctuation 3.char.IsSurrogate 4.char.IsWhitespace 5.char.IsDigit 6.c ...

  7. .net 文件下载

    /** 输入参数* _Request: Page.Request 对象* _Response: Page.Response 对象* _fileName: 下载文件名* _fullPath: 带文件名下 ...

  8. SQL Server索引进阶第十一篇:索引碎片分析与解决

    相关有关索引碎片的问题,大家应该是听过不少,也许也很多的朋友已经做了与之相关的工作.那我们今天就来看看这个问题. 为了更好的说明这个问题,我们首先来普及一些背景知识. 知识普及 我们都知道,数据库中的 ...

  9. Ueditor和CKeditor 两款编辑器的使用与配置

    一丶ueditor 百度编辑器 1.官方文档,演示,下载地址:http://ueditor.baidu.com/website/index.html 2.百度编辑器的好:Editor是由百度web前端 ...

  10. jquery JS 左右方向键

    $(function (){ // $(document).keydown(function(e){ var code=e.which; switch (code) { case 38: //上 br ...