转:为什么C++中空类和空结构体大小为1?

参考:http://www.spongeliu.com/260.html

为什么C++中空类和空结构体大小为1?

On November 17, 2010, in C语言语言学习, by sponge

这篇文章是一篇译文,跟上一篇文章相呼应的,原文在这里

对于结构体和空类大小是1这个问题,首先这是一个C++问题,在C语言下空结构体大小为0(当然这是编译器相关的)。这里的空类和空结构体是指类或结构体中没有任何成员。

在C++下,空类和空结构体的大小是1(编译器相关),这是为什么呢?为什么不是0?

这是因为,C++标准中规定,“no object shall have the same address in memory as any other variable” ,就是任何不同的对象不能拥有相同的内存地址。 如果空类大小为0,若我们声明一个这个类的对象数组,那么数组中的每个对象都拥有了相同的地址,这显然是违背标准的。

但是,也许你还有一个疑问,为什么C++标准中会有这么无聊的规定呢?

当然,这样规定显然是有原因的。我们假设C++中有一个类型T,我们声明一个类型T的数组,然后再声明一个T类型的指针指向数组中间某个元素,则我们将指针减去1,应该得到数组的另一个索引。如下代码:

1
2
3
4
5
T array[5];
 
int diff = &array[3] - &array[2];
 
 // diff = 1

上面的代码是一种指针运算,将两个指针相减,编译器作出如下面式子所示的动作:

diff = ((char *)&array[3] - (char *)&array[2]) / sizeof T;

式子应该不难懂把,很明显的一点就是这个式子的计算依赖于sizeof T。虽然上面只是一个例子,但是基本上所有的指针运算都依赖于sizeof T。

好,下面我们来看,如果允许不同的对象有相同的地址将会引发什么样的问题,看下面的例子:

1
2
3
4
 &array[3] - &array[2] = &array[3] - &array[1]
                       = &array[3] - &array[1]
                       = &array[3] - &array[0]
                       = 0

我们可以看到,在这个例子中,如果每个对象都拥有相同地址,我们将没有办法通过指针运算来区分不同的对象。还有一个更严重的问题,就是如果 sizeof T是0,就会导致编译器产生一个除0的操作,引发不可控的错误。

基于这个原因,如果允许结构体或者类的大小为0,编译器就需要实现一些复杂的代码来处理这些异常的指针运算。

所以,C++标准规定不同的对象不能拥有相同的地址。那么怎样才能保证这个条件被满足呢?最简单的方法莫过于不允许任何类型的大小为0。所以编译器为每个空类或者空结构体都增加了一个虚设的字节(有的编译器可能加的更多),这样这些空类和空结构的大小就不会是0,就可以保证他们的对象拥有彼此独立的地址。

时间: 2024-10-15 14:40:26

转:为什么C++中空类和空结构体大小为1?的相关文章

C++中的空类与空结构体大小

今天面试遇到了一个很有意思的问题,即空结构体在C++中所占的内存大小是多少?参见如下代码: #include <iostream> struct S0 { }; int main() { std::cout << sizeof S0 << std::endl; return 0; } 面试官当场提醒了我一下,说如果S0对象所占用的内存大小为0,那么将可以申请无限多个此类型的对象数组,并且大小永远为0.我当时觉得有点道理,不过转念一想,还是有点疑惑. 回来研究了一下,原来

程序猿之---C语言细节29(#define宏大小、空结构体大小、柔性数组不知道你见过没)

主要内容:#define宏大小.空结构体大小.柔性数组 一.#define宏大小 见例子 二.空结构体大小 根编译器有关 三.柔性数组 不常用,可看看 #include <stdio.h> #define N 4 #define STR "abcd" int main() { struct student { }stu; printf("N = %d\n", sizeof(N)); printf("num 5 memery = %d\n&quo

C++ c++与C语言的区别(空结构体)

//区别⑨:空结构体声明(C++版本) #include<iostream> using namespace std; struct A{}; class B{}; void main(){ printf("C++中空结构体内存大小是%d\n", sizeof(A));//打印 1 printf("C++中空类内存大小是%d\n", sizeof(B)); //打印1 //在C++中,空结构体,空类都在内存中占一个字节大小的内存空间 system(&qu

空结构体 — 专题

Introduction 空结构体是没有位段的结构体,以下是空结构体的一些例子: type Q struct{} var q struct{} 但是如果一个结构体没有位段,不包含任何数据,那么他的用处是什么?我们能够利用空结构体完成什么任务? Width 在深入研究空结构体之前,我想先简短的介绍一下关于结构体宽度的知识. 宽度描述了存储一个数据类型实例需要占用的字节数,由于进程的内存空间是一维的,我更倾向于将宽度理解为Size(这个词实在不知道怎么翻译了,请谅解). 宽度是数据类型的一个属性.G

通过反射来获取对应运行时类的完整结构

Class 对象可以调用其方法获取以下这些类的对象,这些类型分别对应着运行时类的某个结构:Field.Method.Constructor.Superclass.Interface.Annotation 通过这些类的对象,可以获取对应运行时类的: 实现的所有接口 所继承的父类 所有构造器 所有方法 所有属性 泛型 注解 package com.cdf.reflection; import java.lang.annotation.Annotation; import java.lang.refl

Class类文件的结构

1.Class文件是一组以8位字节为基础单元的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件中,中间没有任何的分隔符,这使得整个Class文件中存储的内容几乎全部都是程序运行的必要数据,没有空隙存在.当遇到需要占用8位字节以上空间的数据项时,则会按照高位在前的方式分割为若干个8位字节进行存储. 2.按照Java虚拟机规定,Class文件格式采用一种类似C语言结构体的伪机构来存储,这种伪结构中只有两种数据类型:无符号数和表. 3.无符号数属于基本的数据类型,以u1.u2.u4.u8来

java类的基本结构

一.面向对象的基本概念 万物皆对象.对象的实质是属性和行为. 类是具有共同属性和行为的对象的集合.类定义了对象的属性和方法. 分析过程现有对象后有类,开发过程先有类后有对象. 二.类的基本结构 属性:对象数据的描述 方法:对象的行为 构造方法:用于实例化对象 内部类:在类中声明的类(inner class) 块:分静态块与实例块 类的声明:(访问权限修饰符public.default(可忽略不写,为默认))(修饰符final.abstract.synchronized)class  类名{  

字节对齐 空结构体长度

请仔细查看和对比,尤其是注释掉的结果. 1.代码: /* 编辑编译环境:Dev-C++ 4.9.9.2 */ /* source: */ #include "stdio.h" struct S{ }; struct S1{ char a; long b; }; struct S2 { char c; struct S1 d; long long e; }; struct S3{ long b; char a; }; int main(void) { // result: printf(

C++ Primer 学习笔记_20_类与数据抽象(6)_深拷贝与浅拷贝、空类与空数组

C++ Primer 学习笔记_20_类与数据抽象(6)_深拷贝与浅拷贝.空类与空数组 一.深拷贝与浅拷贝 浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换而言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象. 深拷贝:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量.那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象.换而言之,深拷贝把要复制的对象所引用的对象都复制了一遍. 浅拷贝可