`
vaqeteart
  • 浏览: 304127 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

关于sizeof

    博客分类:
  • tmp
 
阅读更多
关于sizeof
sizeof以字节形式给出操作数的存储大小。通过本文我们可以了解sizeof的使用和计算方法。

主要内容:
一、功能
二、使用语法
三、计算方法
四、举例
五、其他

一、功能
===============
sizeof以字节形式给出操作数的存储大小。
sizeof是C语言的一种单目操作符,如C语言的其他操作符++、--等。它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。 

二、使用语法
===============
sizeof有如下两种使用方式:
用于数据类型的sizeof使用形式:"sizeof(type)"。这里,数据类型必须用括号括住。如sizeof(int)。 
用于变量的sizeof使用形式:"sizeof(var_name)"或"sizeof var_name"。变量名可以不用括号括住。如"sizeof (var_name)","sizeof var_name"等都是正确形式。带括号的用法更普遍,大多数程序员采用这种形式。 
注意:sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。如"sizeof(max)"而此时变量max定义为int max(), sizeof(char_v)而此时char_v定义为char char_v [MAX]且MAX未知,sizeof(void)都不是正确形式。 

三、计算方法
===============
1,基本数据类型大小
sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。对于int, unsigned int, short int, unsigned short, long int, unsigned long, float, double, long double等基本类型的大小,没有明确的规定,但是一般应当记住如下原则:
a ANSI C规定char类型一定是8位。
b long类型的长度和cpu字长一样。
c int长度没有规定,但是不比short短不比long长,并且linux上支持的所有体系中int长度目前都是32位。
d short和int类似,目前linux上长度都是16位。
例如,一般常见的基本类型大小信息如下(32位机Linux平台)
char为1byte;
int为4byte;
unsigned int为4byte;
short int为2byte;
unsigned short为2byte;
long int为4byte;
unsigned long为4byte;
float为4byte;
double为8byte;
long double为12byte;

2,指针类型大小
当操作数是指针时,sizeof依赖于编译器。例如Microsoft C/C++7.0中,near类指针字节数为2,far、huge类指针字节数为4。一般Unix的指针字节数为4。 

3,数组类型大小
当操作数具有数组类型时,其结果是数组的总字节数。如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。

4,结构和联合
联合类型操作数的sizeof是其最大字节成员的字节数。结构类型操作数的sizeof是其对象包括任何填充在内的总字节数。
关于结构大小和结构变量存放地址,本文后面例子中将重点进行介绍,确定方法依照编译器有所不同,大致规则如下: 
a) 成员变量在结构中被声明的顺序和其在内存中的存储顺序。第一个结构成员变量相对整个结构的地址偏移为0。
b) 结构成员变量的偏移地址由编译器中设置的"最大对齐参数",以及该结构变量的类型大小决定。整个结构的大小由最大结构成员变量类型或编译器中设置的"最大对齐参数"决定。这里的最大对齐方式可以由不同的编译器的特定关键字来设置。默认一般是cpu的字长,例如32位机器为4字节。
结构大小和地址计算方法如下:
a)结构成员变量的偏移地址计算:偏移地址为该成员类型大小和最大对齐字节大小两者较小者的整数倍。如果当前偏移位置不满足条件,那么就填充至满足,才开始存放该结构变量。尺寸计算:就是该成员类型的大小。
b)结构变量偏移地址计算:偏移地址为该结构中最大成员大小和最大对齐字节大小两者较小者的整数倍。尺寸计算:整个结构大小为结构中最大成员变量与最大对齐方式两者较小者的整数倍,如果当前所有成员大小之和小于这个整数倍就会添充直至达到要求。
总之,首先假定好最大字节对齐方式,然后确定每个成员起始地址(该成员类型大小以及最大字节对齐的较小者的倍数),最后确定结构总大小(最大成员大小和最大字节对齐较小者的倍数)。(先每个成员,再整体,不满足则填充)

四、举例
===============
下面是整理的说明VC到底怎么样来存放结构的(可以参见后面参考资料,这里没有对其进行严格的实践),其它编译器处理方式有所不同,但是大体都一致。

*结构定义如下:
struct MyStruct
{
double dda1;
char dda;
int type
};
大小计算方式如下:
为上面的结构分配空间的时候,VC根据成员变量出现的顺序和对齐方式,先为第一个成员dda1分配空间,该成员类型为double,其起始地址跟结构的起始地址相同(偏移量 0 为sizeof(double)的倍数),占用sizeof(double)=8个字节;接下来为第二个成员dda分配空间,该成员类型为char,其想对于结构的起始地址的偏移量为8(偏移量8为sizeof(char)的倍数),该成员变量占用 sizeof(char)=1个字节;接下来为第三个成员type分配空间,该成员类型为int,相对于结构的起始地址的偏移量为9,不是sizeof (int)=4的倍数,为了满足对齐方式对偏移量的约束问题,VC自动填充3个字节(这三个字节没有放什么东西),这时下一个可以分配的地址对于结构的起始地址的偏移量为12,刚好是sizeof(int)=4的倍数,所以把type存放在偏移量为12的地方,该成员变量占用sizeof(int)=4个字节;这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:8+1+3+4=16,刚好为结构的字节边界数(即结构中占用最大空间的类型所占用的字节数sizeof(double)=8)的倍数,所以没有空缺的字节需要填充。所以整个结构的大小为:sizeof(MyStruct)=8+1+ 3+4=16,其中有3个字节是VC自动填充的,没有放任何有意义的东西。

*交换一下上面的MyStruct的成员变量的位置,使它变成下面的情况:
struct MyStruct
{
char dda;
double dda1;
int type
};
这时候大小计算方式如下:
为上面的结构分配空间的时候,VC根据成员变量出现的顺序和对齐方式,先为第一个成员dda分配空间,该成员类型为char,其起始地址跟结构的起始地址相同(偏移量 0 为sizeof(char)的倍数),占用sizeof(char)=1个字节;接下来为第二个成员dda1分配空间,该成员类型为double,其想对于结构的起始地址的偏移量为1,不是sizeof (double)=7的倍数,为了满足对齐方式对偏移量的约束问题,VC自动填充7个字节(这7个字节没有放什么东西),这时下一个可以分配的地址对于结构的起始地址的偏移量为8,刚好是sizeof(double)=8的倍数,所以把dda1存放在偏移量为8的地方,该成员变量占用sizeof(double)=8个字节;接下来为第三个成员type分配空间,该成员类型为int,相对于结构的起始地址的偏移量为16,刚好是sizeof(int)=4的倍数,所以把type存放在偏移量为16的地方,该成员变量占用sizeof(int)=4个字节;这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:1+7+8+4=20,不满足结构的字节边界数(即结构中占用最大空间的类型所占用的字节数sizeof(double)=8)的倍数,所以VC自动填充4个字节。综上,整个结构的大小为:sizeof(MyStruc)为1+7+8+4+4=24。其中总的有7+4=11个字节是VC自动填充的,没有放任何有意义的东西。

*自己设置对齐方式:
我们也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式。VC中提供了#pragma pack(n)来设定变量以n字节对齐方式。这里n字节对齐的意思是说:(1)结构成员变量存放的起始地址的偏移量按照两种情况确定。第一、如果设置的n大于等于该成员变量所占用的字节数,那么偏移量必须满足默认的对齐方式(也就是以该成员变量的类型大小对齐),第二、如果设置的n小于该成员变量的类型所占用的字节数,那么成员变量的偏移量为n的倍数,而不用满足默认的对齐方式。(2)结构的总大小也按下面两种情况确定:如果n大于最大的成员变量类型所占用的字节数,那么结构的总大小为占用空间最大的成员变量所占用的空间数的倍数;否则,必须为n的倍数。
下面举例说明其用法。
#pragma pack(push) //保存对齐状态
#pragma pack(4)//设定为4字节对齐
struct test
{
char m1;
double m4;
int m3;
};
#pragma pack(pop)//恢复对齐状态
以上结构的大小为16,为此分配空间的时候,首先为m1分配空间,该成员类型为char,同时sizeof(char)为1,小于我们自己设定的4字节,所以起始地址按照sizeof(char)=1对齐,和结构起始地址一样,(偏移为0为sizeof(char)的倍数),m1占用1个字节;接着开始为m4分配空间,该成员类型为double,同时sizeof(double)为8,大于我们自己设定的4字节,所以按照我们设置的4字节对齐,这时其偏移量为1,需要补足3个字节,使其偏移量为4,满足为n=4的倍数,m4占用8个字节;接着为m3分配空间,该成员类型为int,sizeof(int)为4,和设定的4字节一样,所以按照4字节对齐,这时其偏移量为12,正好满足为4的倍数,m3占用4个字节。这时已经为所有成员变量分配了空间,对于整个结构变量,其中最大类型为double为8字节,大于我们设定的4字节,所以结构总大小采用n=4的倍数,这里目前共分配了16个字节正好是4的倍数,所以结构大小为1+3+8+4=16。同理,如果把上面的#pragma pack(4)改为#pragma pack(16),那么我们可以得到结构的大小为24。
从上面的例子我们可以看出,调整结构成员变量的位置,或者设置对齐方式,都会影响该结构变量的存储效率。同时设置对齐方式可能会影响速度。

五、其他
===============
有几个额外需要注意的地方:
1,sizeof应用在C++中的类和结构的处理情况是相同的。但有两点需要注意,第一、结构或者类中的静态成员不对结构或者类的大小产生影响,因为静态变量的存储位置与结构或者类的实例地址无关。 第二、没有成员变量的结构或类的大小为1,因为必须保证结构或类的每一个实例在内存中都有唯一的地址。

2,经过实践对于Linux如下代码输出分别如下:
1)c语言源文件main.c内容如下:
  1 #include <stdio.h>
  2 struct mystruct
  3 {
  4 };
  5 int main(int argc, char *argv[])
  6 {
  7     printf("%d\n",sizeof(struct mystruct));
  8     return 0;
  9 }
采用"gcc main.c"编译之后,输出结果显示"0",即空结构体大小为0。
采用"g++ main.c"编译之后,输出结果显示"1",即空结构体大小为1。

2)c++语言源文件main.cpp如下:
  1 #include <cstdio>
  2 class myclass
  3 {
  4 };
  5
  6 struct mystruct
  7 {
  8 };
  9 int main(int argc, char *argv[])
10 {
11     printf("%d,%d\n",sizeof(myclass),sizeof(struct mystruct));
12     return 0;
13 }
采用"gcc main.cpp"无法编译。
采用"g++ main.cpp"编译之后,输出结果显示"1,1"即空类和结构体大小均为1。


参考资料:
http://hi.baidu.com/ciw_blue/blog/item/28d74c3f6b134cea54e7239e.html

作者:QuietHeart
Email:quiet_heart000@126.com
日期:2011年8月2日
分享到:
评论

相关推荐

    C 语言关于sizeof() 和 strlen()区别.pdf

    在C语言中,`sizeof()` 和 `strlen()` 都是用来获取数据大小的函数,但它们的作用对象和计算方式有着显著的差异。理解这些差异对于优化代码和避免内存问题至关重要。 `sizeof()` 是一个运算符,而不是函数,它返回...

    sizeof用法

    这个是一段关于sizeof的用法总结,现在拿过来和大家分享一下

    C语言中关于sizeof 和 strlen的区别分析

    1、编译时计算运算符sizeof,可用类型或变量做参数,计算占用内存的大小。sizeof后若是类型必须加括弧,若是变量名可不加括弧。sizeof(x)可用来定义数组维数如: 代码如下: printf(“%d\n”, sizeof(short));  ...

    解析C语言中的sizeof.rar

    在C语言中,`sizeof`是一个非常重要的运算符,它用于获取任何数据类型或变量所占用的内存字节数。这个运算符对于理解和优化代码、处理内存分配以及了解底层计算机工作原理都至关重要。下面我们将详细探讨`sizeof`的...

    matlab开发-sizeof

    在MATLAB编程环境中,`sizeof`是一个非常重要的函数,它用于获取MATLAB中内置数据类型所占用的内存字节数。这个知识点对于理解和优化MATLAB程序的性能、内存使用以及理解数据存储方式至关重要。下面我们将深入探讨`...

    sizeof运算符的使用

    以下是关于`sizeof`运算符的详细解释。 1. **`sizeof`运算符的基本用法** `sizeof`运算符是 sizeof(expression) 的形式,其中expression可以是类型名或者变量名。它返回表达式或类型所占的字节数。例如: ```cpp...

    详细讲解sizeof的使用

    ### 详细讲解 `sizeof` 的使用 #### 一、`sizeof` 概念解析 `sizeof` 是 C 语言中的一个单目操作符,用于获取指定类型或变量的存储大小,单位为字节。它不同于普通的函数调用,而是直接在编译阶段就被解析。 ####...

    sizeof 的用法(大全)

    在C/C++编程语言中,`sizeof`是一个非常重要的运算符,用于获取变量或类型所占用内存的字节数。本篇文章将全面讲解`sizeof`的用法,并将其与常用的字符串长度函数`strlen()`进行比较,帮助开发者深入理解并解决在...

    MFC源代码 SIZEOF.02

    MFC源代码 SIZEOF.02MFC源代码 SIZEOF.02MFC源代码 SIZEOF.02MFC源代码 SIZEOF.02MFC源代码 SIZEOF.02MFC源代码 SIZEOF.02MFC源代码 SIZEOF.02MFC源代码 SIZEOF.02MFC源代码 SIZEOF.02MFC源代码 SIZEOF.02MFC源代码 ...

    C++sizeof使用规则及陷阱分析

    ### C++ `sizeof` 使用规则及陷阱分析 #### 一、`sizeof` 概念介绍 在C++中,`sizeof` 是一个关键字,用于获取变量或类型(包括聚合类型)所占用的存储空间大小(以字节为单位)。这个关键字返回一个 `size_t` ...

    sizeof计算struct大小

    sizeof 计算 struct 大小 sizeof 是一个 unary 运算符,用于计算变量或类型的大小,以字节为单位。在 C 语言中,sizeof 运算符可以应用于变量、数组、结构体、联合体、枚举类型等各种数据类型。sizeof 运算符的结果...

    详细解析C语言中的sizeof

    ### 详细解析C语言中的`sizeof` #### 一、`sizeof`的概念 `sizeof`是C语言中的一个单目操作符,类似于其他操作符如`++`和`--`等。需要注意的是,`sizeof`不是函数,而是用来获取操作数(可以是一个表达式或类型名...

    sizeof和strlen区别

    在C/C++编程语言中,`sizeof`和`strlen`是两个非常重要的操作符,它们分别用于获取数据类型的大小和字符串的长度。然而,这两个操作符有着本质的区别,理解和掌握它们的区别对于编写高效且无误的代码至关重要。 ...

    sizeof函数使用注意事项

    以下是关于`sizeof`的一些核心知识点: 1. **基本类型大小**:`sizeof`可以用于获取基本数据类型的大小,如`int`、`char`、`float`、`double`等。例如,`sizeof(int)`通常返回4(在32位系统中)或8(在64位系统中)...

    sizeof与strlen区别

    ### sizeof与strlen的区别详解 #### 一、概述 在C/C++编程语言中,`sizeof`和`strlen`是两个非常重要的概念,它们都用于获取有关数据的信息,但各自的作用和应用场景有所不同。本文将详细介绍这两个操作符/函数的...

    关于字符常量

    关于 sizeof 运算符 sizeof 运算符是用来测算某个值或者某个类型的数据所需占用的内存字节数的。 sizeof(int) 可以测得 int 类型的数据占用内存的字节数,结果为 4 sizeof(3 + 4) 可以测得表达式 3 + 4 的值占用...

    深入理解Sizeof

    ### 深入理解 `sizeof` 运算符 #### 引言 在日常的编程工作中,`sizeof` 是一个非常常见的运算符,用于获取变量或类型所占用的内存大小。然而,对于初学者而言,`sizeof` 的行为有时会显得有些神秘。本文将详细解释...

Global site tag (gtag.js) - Google Analytics