(非)静态成员变量

合集下载

java 试题

java 试题

一、填空题1、Java的三大体系分别是_JavaSE_____、_JavaEE_____、_JavaME_____。

2、Java程序的运行环境简称之为JRE_____。

3、编译Java程序需要使用_javac_____命令。

4、javac.exe和java.exe两个可执行程序存放在JDK安装目录的bin______目录下。

5、path______环境变量用来存储Java的编译和运行工具所在的路径,而_classpath_____环境变量则用来保存保存Java虚拟机要运行的“.class”文件路径。

二、选择题1、以下选项中,哪些属于JDK工具?(多选)ABCDA、Java编译器B、Java运行工具C、Java文档生成工具D、Java打包工具2、Java属于以下哪种语言?CA、机器语言B、汇编语言C、高级语言34种?BA、5、5、javac 和项?BA.1、简述2、2、类、GUI程序,那开发人员JRE部分,第二章、Java int 整型,占双精和false2、义3、方法重载指的是在一个类中可以声明多个同名的方法,而方法中参数的个数或者数据类型不一致。

调用这些同名的方法时,JVM会根据实际参数的不同绑定到不同的方法冒泡排序:publicclassTest03{publicstaticvoidmain(String[]args){int[]arr={25,24,12,76,101,96,28} ;for(inti=0;i<arr.length-1;i++){//定义内层循环for(intj=0;j<arr.length-i-1;j++){if(arr[j]>arr[j+1]){//比较相邻元素//下面的三行代码用于交换两个元素inttemp=arr[j];arr[j]=arr[j+1];arr[j+1]=temp;}}}for(inti=0;i<arr.length;i++){+"");//打印元素和空格}}1、构造方法是类的一个特殊成员,它会在类实例化对象时被自动调用。

静态变量与非静态变量的区别

静态变量与非静态变量的区别

静态变量与非静态变量的区别静态变量:静态变量使用static修饰符进行声明在所属类被装载时创建通过类进行访问所属类的所有实例的同一静态变量都是同一个值非静态变量:不带有static修饰符声明的变量称做非静态变量在类被实例化时创建通过对象进行访问同一个类的不同实例的同一非静态变量可以是不同的值。

对于自动变量,它属于动态存储方式。

但是也可以用static定义它为静态自动变量,或称静态局部变量,从而成为静态存储方式。

由此看来,一个变量可由static进行再说明,并改变其原有的存储方式。

下面介绍静态变量与非静态变量的区别如下:1.内存分配静态变量在应用程序初始化时,就存在于内存当中,直到它所在的类的程序运行结束时才消亡;而非静态变量需要被实例化后才会分配内存。

2.生存周期静态变量生存周期为应用程序的存在周期;非静态变量的存在周期取决于实例化的类的存在周期。

3.调用方式静态变量只能通过“类.静态变量名”调用,类的实例不能调用;非静态变量当该变量所在的类被实例化后,可通过实例化的类名直接访问。

4.共享方式静态变量是全局变量,被所有类的实例对象共享,即一个实例的改变了静态变量的值,其他同类的实例读到的就是变化后的值;非静态变量是局部变量,不共享的。

5.访问方式静态成员不能访问非静态成员;非静态成员可以访问静态成员。

静态变量在类装载的时候分配内存,以后创建的对象都使用的该内存,相应的操作也就是对这块内存进行操作。

也可以看作是另类的全局变量。

在WebSerivice中想只进行一次初始化,而不用每次都进行初始化这样占用大量资源。

还可以对调用的服务进行管理,比如想把每次调用的服务进行排队执行,可以将想应信息放到Arraylist中,静态时钟中排队执行。

C#静态构造函数及静态变量静态构造函数:(1)用于对静态字段、只读字段等的初始化。

(2)添加static关键字,不能添加访问修饰符,因为静态构造函数都是私有的。

(3)类的静态构造函数在给定应用程序域中至多执行一次:只有创建类的实例或者引用类的任何静态成员才激发静态构造函数(4)静态构造函数是不可继承的,而且不能被直接调用。

C++类中的静态成员变量和静态成员函数的作用

C++类中的静态成员变量和静态成员函数的作用

数据成员可以分静态变量、非静态变量两种.静态成员:静态类中的成员加入static修饰符,即是静态成员.可以直接使用类名+静态成员名访问此静态成员,因为静态成员存在于内存,非静态成员需要实例化才会分配内存,所以静态成员不能访问非静态的成员..因为静态成员存在于内存,所以非静态成员可以直接访问类中静态的成员.非成静态员:所有没有加Static的成员都是非静态成员,当类被实例化之后,可以通过实例化的类名进行访问..非静态成员的生存期决定于该类的生存期..而静态成员则不存在生存期的概念,因为静态成员始终驻留在内容中..一个类中也可以包含静态成员和非静态成员,类中也包括静态构造函数和非静态构造函数..分两个方面来总结,第一方面主要是相对于面向过程而言,即在这方面不涉及到类,第二方面相对于面向对象而言,主要说明static在类中的作用。

一、在面向过程设计中的static关键字1、静态全局变量定义:在全局变量前,加上关键字static 该变量就被定义成为了一个静态全局变量。

特点:A、该变量在全局数据区分配内存。

B、初始化:如果不显式初始化,那么将被隐式初始化为0(自动变量是随机的,除非显式地初始化)。

C、访变量只在本源文件可见,严格的讲应该为定义之处开始到本文件结束。

例〔摘于C++程序设计教程---钱能主编P103〕://file1.cpp//Example 1#include <iostream.h>void fn();static int n; //定义静态全局变量void main(){n=20;cout < <n < <endl;fn();}void fn(){n++;cout < <n < <endl;}D、文件作用域下声明的const的常量默认为static存储类型。

静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量。

对于一个完整的程序,在内存中的分布情况如以下图:代码区全局数据区堆区栈区一般程序的由new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。

C++静态成员变量和静态成员函数的使用方法总结

C++静态成员变量和静态成员函数的使用方法总结

C++静态成员变量和静态成员函数的使⽤⽅法总结⼀.静态成员变量:类体中的数据成员的声明前加上static关键字,该数据成员就成为了该类的静态数据成员。

和其他数据成员⼀样,静态数据成员也遵守public/protected/private访问规则。

同时,静态数据成员还具有以下特点:1.静态数据成员的定义。

静态数据成员实际上是类域中的全局变量。

所以,静态数据成员的定义(初始化)不应该被放在头⽂件中。

其定义⽅式与全局变量相同。

举例如下:xxx.h⽂件class base{private:static const int _i;//声明,标准c++⽀持有序类型在类体中初始化,但vc6不⽀持。

};xxx.cpp⽂件const int base::_i=10;//定义(初始化)时不受private和protected访问限制.备注:不要在头⽂件中定义(初始化)静态数据成员。

在⼤多数的情况下,这样做会引起重复定义这样的错误。

即使加上#ifndef #define #endif或者#pragma once也不⾏。

2.静态数据成员被类的所有对象所共享,包括该类派⽣类的对象。

即派⽣类对象与基类对象共享基类的静态数据成员。

举例如下:class base{public :static int _num;//声明};int base::_num=0;//静态数据成员的真正定义class derived:public base{};main(){base a;derived b;a._num++;cout<<"base class static data number _numis"<<a._num<<endl;b._num++;cout<<"derived class static data number _numis"<<b._num<<endl;} // 结果为1,2;可见派⽣类与基类共⽤⼀个静态数据成员。

java题库—判断

java题库—判断

第一章:1、CPU指的是运算器和CRT F×2、计算机与一般计算装置的本质区别是它具有存储程序和程序控制功能T*√3、在计算机中,控制器是执行算术运算和逻辑运算的部件,它的任务是对信息进行加工处理。

×4、程序在运行时发现的错误一般是程序语法上的错误。

√*5、第一代计算机时期没有操作系统。

√6、计算机中数值数据一般采用补码形式存储。

√7、利用Java语言可以开发客户端Java小程序和应用程序,以及独立的服务器应用程序等。

√8、Java2技术分为J2EE、J2SE和J2ME,其中J2SE是Java的企业版,用来针对企业级进行应用服务的开发。

×9、Java语言适合开发跨平台的应用程序。

√10、Java语言适合用来开发系统程序,像很多的操作系统及驱动程序都是用Java来编写的。

×11、Java源程序文件扩展名必须为.java,但文件名不必与(主)类名保持一致。

×12、Java的平台无关性主要是依靠JRE实现的。

×13、与Java应用程序(Application)不同,Java Applet程序的运行,需要得到客户端浏览器的支持。

√14、安装JDK时,需要配置环境变量path、classpath和JA V A_HOME。

√第三章:1、J2EE企业版是以企业为环境而开发应用程序的解决方案。

√2、J2ME小型版是致力于消费产品和嵌入式设备的最佳解决方案。

√3、J2SE标准版为桌面开发和低端商务应用提供了可行的解决方案。

√4、Java是区分大小写的语言,关键字的大小写不能搞错,如果把类class写成Class或者CLASS,都是错误的。

√5、Java源程序编写好之后,以文件的形式保存在硬盘或U盘上,源文件的名字可以随便取的,它不一定与程序的主类名一致。

×6、在JDK命令行开发工具中,用编译程序javac.exe编译生成的文件是二进制可执行文件。

第6章【面向对象基础--中】

第6章【面向对象基础--中】

第6章【⾯向对象基础--中】理解封装的概念掌握权限修饰符的使⽤掌握成员变量的私有化掌握构造器的声明与使⽤会声明标准的JavaBean能够写出类的继承格式能够说出继承的特点能够说出⽅法重写的概念以及和重载的区别能够使⽤this关键字解决问题能够使⽤super关键字解决问题能够分析类初始化过程(为⾯试服务)能够分析实例初始化过程(为⾯试服务)能够应⽤多态解决问题理解向上转型与向下转型能够使⽤instanceof关键字判断对象类型了解native关键字掌握final关键字了解Object类的常⽤⽅法会重写Object的常⽤⽅法6.1 封装6.1.1 封装概述1我要⽤洗⾐机,只需要按⼀下开关和洗涤模式就可以了。

有必要了解洗⾐机内部的结构吗?有必要碰电动机吗?我们使⽤的电脑,内部有CPU、硬盘、键盘、⿏标等等,每⼀个部件通过某种连接⽅式⼀起⼯作,但是各个部件之间⼜是独⽴的现实⽣活中,每⼀个个体与个体之间是有边界的,每⼀个团体与团体之间是有边界的,⽽同⼀个个体、团体内部的信息是互通的,只是对外有所隐瞒。

⾯向对象编程语⾔是对客观世界的模拟,客观世界⾥每⼀个事物的内部信息都是隐藏在对象内部的,外界⽆法直接操作和修改,只能通过指定的⽅式进⾏访问和修改。

封装可以被认为是⼀个保护屏障,防⽌该类的代码和数据被其他类随意访问。

适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。

随着我们系统越来越复杂,类会越来越多,那么类之间的访问边界必须把握好,⾯向对象的开发原则要遵循“⾼内聚、低耦合”,⽽“⾼内聚,低耦合”的体现之⼀:⾼内聚:类的内部数据操作细节⾃⼰完成,不允许外部⼲涉;低耦合:仅对外暴露少量的⽅法⽤于使⽤隐藏对象内部的复杂性,只对外公开简单的接⼝。

便于外界调⽤,从⽽提⾼系统的可扩展性、可维护性。

通俗的讲,把该隐藏的隐藏起来,该暴露的暴露出来。

这就是封装性的设计思想。

2通俗的讲,封装就是把该隐藏的隐藏起来,该暴露的暴露出来。

java项目经理招聘笔试题与参考答案(某大型央企)2024年

java项目经理招聘笔试题与参考答案(某大型央企)2024年

2024年招聘java项目经理笔试题与参考答案(某大型央企)(答案在后面)一、单项选择题(本大题有10小题,每小题2分,共20分)1、在Java编程语言中,下列哪个关键字用于定义类?A、classB、interfaceC、enumD、abstract2、以下哪个方法可以实现一个字符串的逆序?A、String.reverse()B、StringBuilder.reverse()C、StringBuffer.reverse()D、String.concat(““)3、下列哪个不是Java的关键字?A、interfaceB、implementsC、includeD、abstract4、关于Java中的构造器,下面说法正确的是哪一个?A、构造器必须与类同名B、构造器可以有返回类型C、构造器不能带有任何参数D、构造器在一个对象被创建时不会自动执行5、以下哪个不属于Java编程语言的特性?A、面向对象编程B、平台无关性C、编译型语言D、事件驱动6、在Java中,以下哪个关键字用于声明一个抽象类?A、interfaceB、classC、abstractD、final7、下列关于Java泛型的描述正确的是:A. 泛型是一种在编译阶段检查类型的机制B. 泛型可以增加程序的运行速度C. 泛型的存在是为了避免类型转换错误D. 泛型类在实例化时需要额外的类型转换8、关于Java中的抽象类和接口,下面说法正确的是:A. 抽象类可以有构造方法,而接口不能有构造方法B. 接口可以包含非抽象方法,而抽象类不可以包含非抽象方法C. 抽象类可以继承多个类,也可以实现多个接口D. 接口可以继承另一个接口,并且可以实现抽象类的方法9、在Java中,以下哪个关键字用于声明一个不能被继承的类?A. abstractB. finalC. privateD. protected 10、在Java中,以下哪个方法用于在多线程环境中安全地读取一个共享变量?A. synchronizedB. wait()C. notify()D. notifyAll()二、多项选择题(本大题有10小题,每小题4分,共40分)1、以下哪些技术栈是Java项目经理在项目中常用的?()A. Spring BootB. Apache MavenC. MySQLD. RedisE. Docker2、以下关于敏捷开发原则的说法,正确的是哪些?()A. 客户合作优于合同谈判B. 迭代开发而非全面详尽的规划C. 集中精力在软件上而非过程和工具D. 追求卓越的技术和对工作的热情E. 短期反馈优于长期预测3、以下哪些是Java编程语言中实现多态性的主要方式?()A、继承B、接口C、方法重写D、内部类4、在Java中,以下哪些是线程同步的方法?()A、synchronized关键字B、wait()方法C、notify()方法D、notifyAll()方法5、关于Java项目管理,以下哪些是项目经理在项目执行阶段需要关注的关键点?()A、项目进度管理B、项目质量管理C、项目风险管理D、项目沟通管理E、项目成本管理6、以下关于Java项目持续集成(CI)的说法中,正确的是?()A、持续集成是一种软件开发实践,它强调频繁地合并代码变更。

静态函数 静态数据成员与静态成员函数 为什么虚函数必须是非静态成员函数 构造函数能为static吗

静态函数 静态数据成员与静态成员函数 为什么虚函数必须是非静态成员函数 构造函数能为static吗

静态函数静态数据成员与静态成员函数为什么虚函数必须是非静态成员函数构造函数能为static吗?2009-07-05 14:27静态函数用static声明的函数是静态函数。

静态函数可以分为全局静态函数和类的静态成员函数。

Static关键字在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化,对于该类的所有对象来说,static成员变量只有一份。

用static声明的方法是静态方法,在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员。

静态方法不再是针对于某个对象调用,所以不能访问非静态成员。

可以通过对象引用或类名(不需要实例化)访问静态成员C++类静态数据成员与类静态成员函数函数调用的结果不会访问或者修改任何对象(非static)数据成员,这样的成员声明为静态成员函数比较好。

且如果static int func(....)不是出现在类中,则它不是一个静态成员函数,只是一个普通的全局函数,只不过由于static的限制,它只能在文件所在的编译单位内使用,不能在其它编译单位内使用。

静态成员函数的声明除了在类体的函数声明前加上关键字static,以及不能声明为const或者volatile之外,与非静态成员函数相同。

出现在类体之外的函数定义不能制定关键字static。

静态成员函数没有this指针。

在没有讲述本章内容之前如果我们想要在一个范围内共享某一个数据,那么我们会设立全局对象,但面向对象的程序是由对象构成的,我们如何才能在类范围内共享数据呢?这个问题便是本章的重点:声明为static的类成员或者成员函数便能在类的范围内共同享,我们把这样的成员称做静态成员和静态成员函数。

下面我们用几个实例来说明这个问题,类的成员需要保护,通常情况下为了不违背类的封装特性,我们是把类成员设置为protected(保护状态)的,但是我们为了简化代码,使要说明的问题更为直观,更容易理解,我们在此处都设置为public。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

C++中为什么不能在类定义中初始化非静态成员变量,只能在构造函数中初始化?答:首先,类究竟什么?类是一个对事物具体抽象的模型,注意,它仅是一个抽象的、慨念上的东东。

从程序设计层面看,它仅是一个声明,并不代表一个具体的实例,即使它有成员函数的定义,但在内存实例这个层面,它什么也没有!什么都没有,你到那儿去初始化它的成员x呢? 而且,从类的语意来看,它表示有无限个具有相似性(不是相同性)的对象实例的抽象慨括,非静态成员变量对类来说,是一个变化的值(有无穷的解),它是类的可变部份,语言以及类的设计者不能以相同的值去初始化其可变部份(x)!但对类的不变部份,语言还是适当的允许你在类中去初始化,例如整型int及类整型(long、char等)等静态常量你还是可以在类中初始化它们的!定义类的时候并没有分配内存,这时候赋值的话值放在哪里呢? 当用类构造对象的时候首先分配内存然后调用构造函数,这时候才可以初始化非静态成员变量. 静态成员变量定义的时候在静态存储区中就分配了内存所以可以初始化.静态成员变量在C++中(以及其他一些语言,如C#,Java 等面向对象的语言中)类的成员变量被声明为static(称为静态成员变量),意味着它为该类的所有实例所共享,也就是说当某个类的实例修改了该静态成员变量,其修改值为该类的其它所有实例所见。

比如在某个类A中声明一个static int number;初始化为0。

这个number就能被所有A的实例共用。

在A的构造函数里加上number++,在A的析构函数里加上number--。

那么每生成一个A的实例,number就加一,每销毁一个A的实例,number就减一,这样,number就可以记录程序中共生成了多少个A的实例。

这只是静态成员的一种用法而已。

静态成员函数调用非静态成员变量程序最终都将在内存中执行,变量只有在内存中占有一席之地时才能被访问。

类的静态成员(变量和方法)属于类本身,在类加载的时候就会分配内存,可以通过类名直接去访问;非静态成员(变量和方法)属于类的对象,所以只有在类的对象产生(创建类的实例)时才会分配内存,然后通过类的对象(实例)去访问。

在一个类的静态成员中去访问其非静态成员之所以会出错是因为在类的非静态成员不存在的时候类的静态成员就已经存在了,访问一个内存中不存在的东西当然会出错。

(访问的这个非静态成员必须是属于某个实例才行)C++会区分两种类型的成员函数:静态成员函数和非静态成员函数。

这两者之间的一个重大区别是,静态成员函数不接受隐含的this自变量。

所以,它就无法访问自己类的非静态成员。

静态数据成员在类中,静态成员可以实现多个对象之间的数据共享,并且使用静态数据成员还不会破坏隐藏的原则,即保证了安全性。

因此,静态成员是类的所有对象中共享的成员,而不是某个对象的成员。

使用静态数据成员可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。

静态数据成员的值对每个对象都是一样,但它的值是可以更新的。

只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。

静态数据成员的使用方法和注意事项如下:1、静态数据成员在定义或说明时前面加关键字static。

2、静态成员初始化与一般数据成员初始化不同。

静态数据成员初始化的格式如下:<数据类型><类名>::<静态数据成员名>=<值>这表明:(1) 初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆。

(2) 初始化时不加该成员的访问权限控制符private,public等。

(3) 初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员。

3、静态数据成员是静态存储的,它是静态生存期,必须对它进行初始化。

4、引用静态数据成员时,采用如下格式:<类名>::<静态成员名> (静态成员属于类的,不属于某个对象)静态成员函数静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。

因此,对静态成员的引用不需要用对象名。

在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静态成员。

如果静态成员函数中要引用非静态成员时,可通过对象来引用。

下面通过例子来说明这一点。

#include <iostream>using namespace std;class M{public:M(int a) { A=a; B+=a;}static void f1(M m);private:int A;static int B;};void M::f1(M m){cout<<"A="<<m.A<<endl; //静态成员函数中通过对象来引用非静态成员cout<<"B="<<B<<endl;}int M::B=0; //静态数据成员初始化的格式<数据类型><类名>::<静态数据成员名>=<值>void main(){ M P(5),Q(10); //初始化的时候调用构造函数.M::f1(P); //静态成员函数调用时不用对象名M::f1(Q); }读者可以自行分析其结果。

从中可看出,调用静态成员函数使用如下格式:<类名>::<静态成员函数名>(<参数表>);运行结果:A=5B=15A=10B=15请问string s ;string *s = new string();一个是实例,一个是指针string s ;//栈中,自动释放,局部生命期,直接操作string *s = new string();//堆中,显式释放,全局生命期,通过指针间接操作#pragma在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。

#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。

依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。

没设置对齐方式的时候.简单的说,2句话:1.结构中每个成员到结构首地址的偏移为自身大小的整数倍.2.结构体大小,是整个结构体中最大的成员的大小的整数倍.而设置对齐方式后:1.结构中每个成员到结构首地址的偏移为min(自身大小,设置值)的整数倍.2.结构体大小,是整个结构体中min(最大的成员,设置值)的大小的整数倍.内存对齐好处1 是提高效率;2 是提高移植性,在保证对齐的前提下,程序将具有更好的移植性...cpu对内存的访问周期上考虑的,许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,这就是所谓的内存对齐,而这个k则被称为该数据类型的对齐模数(alignment modulus)。

这种强制的要求一来简化了处理器与内存之间传输系统的设计,二来可以提升读取数据的速度。

比如这么一种处理器,它每次读写内存的时候都从某个8倍数的地址开始,一次读出或写入8个字节的数据,假如软件能保证double类型的数据都从8倍数地址开始,那么读或写一个double类型数据就只需要一次内存操作。

否则,我们就可能需要两次内存操作才能完成这个动作,因为数据或许恰好横跨在两个符合对齐要求的8字节内存块上。

Win32平台下的微软C编译器(cl.exe for 80x86)在默认情况下采用如下的对齐规则: 任何基本数据类型T的对齐模数就是T的大小,即sizeof(T)。

比如对于double类型(8字节),就要求该类型数据的地址总是8的倍数,而char类型数据(1字节)则可以从任何一个地址开始。

struct foo{char c1;short s;char c2;int i;};无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。

原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。

一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。

一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。

某些操作双四字的指令需要内存操作数在自然边界上对齐。

如果操作数没有对齐,这些指令将会产生一个通用保护异常(#GP)。

双四字的自然边界是能够被16整除的地址。

其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。

编译器对内存对齐的处理缺省情况下,c/c++编译器默认将结构、栈中的成员数据进行内存对齐。

因此,上面的程序输出就变成了:c1 00000000, s 00000002, c2 00000004, i 00000008。

编译器将未对齐的成员向后移,将每一个都成员对齐到自然边界上,从而也导致了整个结构的尺寸变大。

尽管会牺牲一点空间(成员之间有空洞),但提高了性能。

也正是这个原因,我们不可以断言sizeof(foo) == 8。

在这个例子中,sizeof(foo) == 12。

如何避免内存对齐的影响那么,能不能既达到提高性能的目的,又能节约一点空间呢?有一点小技巧可以使用。

比如我们可以将上面的结构改成:struct bar{char c1;char c2;int i;};这样一来,每个成员都对齐在其自然边界上,从而避免了编译器自动对齐。

在这个例子中,sizeof(bar) == 8。

这个技巧有一个重要的作用,尤其是这个结构作为API的一部分提供给第三方开发使用的时候。

第三方开发者可能将编译器的默认对齐选项改变,从而造成这个结构在你的发行的DLL中使用某种对齐方式,而在第三方开发者哪里却使用另外一种对齐方式。

这将会导致重大问题。

比如,foo结构,我们的DLL使用默认对齐选项,对齐为c1 00000000, s 00000002, c2 00000004, i 00000008,同时sizeof(foo) == 12。

而第三方将对齐选项关闭,导致c1 00000000, s 00000001, c2 00000003, i 00000004,同时sizeof(foo) == 8。

相关文档
最新文档