来源:http://faq.csdn.net/read/197242.html
sizeof
OK,从抄书开始。
C 程序设计语言 第二版 中文版 P114
C 提供了一个编译时的一元运算符,称为 sizeof,可用来计算任一对象的大小。表达式
sizeof 对象
和
sizeof ( 类型名 )
返回一个整型值,它等于指定对象或类型所占存储空间的字节数。(严格说来,sizeof 的返回值是无符号整数值 size_t,它的类型在头文件 <stddef.h> 中定义)
P115 :附录 A.7.4.8
sizeof 运算符用于求存储其运算分量类型的对象所需要的字符数。运算分量或者为一个未求值的表达式,或者为一个由括号扩起的类型名字。当 sizeof 被用于 char 类型时,其值为 1;当用于数组时,其值为数组中字节的总数。当用于结构或联合时,结果是对象中的字节数,包括任何使对象平铺为数组所需要的填充空间:有 n 个元素的数组的大小将是一个元素大小的 n 倍。此运算符不能用于函数类型和不完全类型的运算分量,也不能用于位字段。结果是一个无符号整形常量,具体的类型由实现定义。在标准头文件 <stddef.h> (见附录B)中,这一类型被定义为 size_t 类型。
P83 :5.3 指针与数组
当把一个数组名字传递给一个函数时,实际上传递的是该数组第一个元素的位置。由于一个数组名字参数就是一个指针,所以在被调用函数中,与数组名字参数对应的变元是一个包含地址值的局部变量。
下面开始灌水。
《C 程序设计语言》(作者 K&R,ISBN: 7-111-07589-7,出版:机械出版社,原书名 The C Programming Language,简称 TCPL)绝对是一本书。不论你学习的是 C 还是 C++,都应该成为案头必备书目。全书 250 页上下,售价不足 30 RMB,但是内容涵盖整个 ANSI C 89 标准以及 C 语言标准库,甚至包含了一份 C 89 标准的解释,绝对物超所值。书中对指针、数组、函数等 C 语言基础的讲解非常精辟易懂,初学者可以轻易理解。
[ sizeof! sizeof! sizeof! ... ]
哦哦哦,我听到了我听到了……我知道我说的是 sizeof,但是你们也不应该这样反对我做一下公益广告嘛~[ 头一偏,伸手接住一个鸡蛋 ] 哪位好心,扔个西红柿过来?我晚饭下饭的菜就有了……
回到 sizeof。上文说明,sizeof 有两种写法: sizeof 对象 或者 sizeof ( 类型 )。不过现如今最常见的写法是一概加上 (),写成类似函数调用的形式(方便宏替换哦~)。话虽如此,千万不要以为 sizeof 是任何意义上的函数调用(或者宏)。它,伟大的、神圣的、独一无二的 sizeof 大侠,是一个运算符。知道什么叫做运算符吗?在 C 语言中,运算符以为着“神圣不可侵犯”。不过 sizeof,作为一个运算符,即使在 C++ 中,仍然是神圣不可侵犯的:因为它紧密地关系到了内存的分配等等底层事务的合法运作。
我们写一个 C 程序(注意,是 C,不是 C++ ……虽然在很大程度上对 C++ 也成立),直接玩弄于股掌之间的,都是存在于栈上的内存颗粒。它们包括各种 auto 对象:int, double, 一般的 struct 对象实例。当他们所在的 scope 完结的时候(也就是他们所在的花括号结束的时候—— for 中的迭代子变量是一个特例),这个变量就超出生命周期,不能继续使用了。对于 C++ 类对象,这时系统会“自动”调用它的析构函数。如果一个对象是被动态分配在堆上,那么我们能操作它的方法只有通过它的地址来进行间接操作——通过一个保存了它的地址的指针来操作这个对象。于是我给他一个说法,说这个堆对象在栈上的“投影”就是这个指针。这个指针本身是 auto 的,超过生命期就不会再次被使用;但是当指针超出生命期的时候堆对象根本不会收到影响——我们只能操作栈上的对象。因此,当我们使用 sizeof 的时候,时刻牢记,我们取得的是这个栈上面投影的大小,而不论我们通过它,操作的是一个什么样的对象。
int main()
{
const char * str = "abcdefg";
char str_stack [] = "abcdefg";
}
上面代码中,str 的类型是一个 char *,也就是一个“指向 char 类型内存的指针”,因此在 32 位平台,sizeof (str) 应该是 4。而 str_stack 的类型是 char[8] ——这里,它的整个字符串都在栈上,而不是在字符串池或者全局、静态、堆之类的任何地方。因此我们 sizeof (str_stack) 就是在 sizeof (char [8]),得到的自然是 8。
关于指针和数组的更多详情,敬请参考 [C/C++ 值班室] 无锋之刃 的两片精彩解说。
http://community.csdn.net/Expert/TopicView1.asp?id=3172383
------------------------------------------------------------------
辣子鸡丁补充:
to ctbt007(afo)
class A
{
private:
int _i;
void func();
virtual vfunc(); //因为这个,所以就有vptr,4bytes
}
-----------------------------------------------------------------
关于 alignment
alignment 一向成为各种猜疑、困惑的来源,尤其是在初学者眼睛里面。为什么呢?看看
struct T
{
int a;
int b;
};
sizeof (struct T) == 8 == sizeof (a) + sizeof(b)
然后——
struct T2
{
char a;
int b;
};
sizeof (struct T2) == ?
5 ? 错误!一般情况下,还是 8!为什么不是 char (a) + char (b) 了呢?
话说这个 Intel 自从很多年前(似乎是 486 年代吧)就宣布,CPU 进入了 32 位时代~这个 32 位是什么意思?它表示,CPU 能处理的“标准”字节宽度是 32 位,也就是 4 个 byte 了。int 被规定成 32 位就是为了适应 CPU 的特性:32 位是 32 位 CPU 上面存取最快的单位——在 TC/DOS 下就是 16 位,在 IA64/AMD64 平台上就是 64 位。当 CPU 在读取内存的时候,一次可以读取一个标准字长的单位,这样效率是最高的。编译器为了优化程序速度,会努力让各个变量适应这个要求,所以在 struct T2 的 a 后面,添加了三个垃圾数据字节 dummy bytes,这样保证 CPU 读取 b 的时候效率达到最高。这种添加 dummy bytes 的恶劣行为,被成为“字节对齐”,或者“补齐”,或者 data alignment。。。都是它了!
VC 中可以通过特别的指令修改默认对齐方式:pack 指令
#pragma pack (1)
会将对齐方式修改成 1byte,这样 sizeof struct T2 就成为了 5 ……没有试验过,错了别打人!
如果不是出于 cross compiling 考虑,默认还是不要修改的比较好……