sizeof计算方法

Cpp代码
// Example of the sizeof keyword  
size_t i = sizeof( int );   

struct align_depends {  

    char c;  
    int i;  
};  
size_t size = sizeof(align_depends); // The value of size depends on   
                                   // the value set with /Zp or   
                                   // #pragma pack  

int array[] = { 1, 2, 3, 4, 5 };     // sizeof( array ) is 20   

                                      // sizeof( array[0] ) is 4   
size_t sizearr =                        // Count of items in array  
   sizeof( array ) / sizeof( array[0] );
// Example of the sizeof keyword
size_t i = sizeof( int );

struct align_depends {
    char c;
    int i;
};
size_t size = sizeof(align_depends); // The value of size depends on
                                   // the value set with /Zp or
                                   // #pragma pack

int array[] = { 1, 2, 3, 4, 5 };     // sizeof( array ) is 20
                                      // sizeof( array[0] ) is 4
size_t sizearr =                        // Count of items in array
   sizeof( array ) / sizeof( array[0] );
<script src="ms-its:dsmsdn.chm::/html/msdn_footer.js"></script>

1. 用法
1.1 sizeof和new、delete等一样,是关键字,不是函数或者宏。
1.2 sizeof返回内存中分配的字节数,它和操作系统的位数有关。例如在常见的32位系统中,int类型占4个字节;但是在16位系统中,int类型占2个字节。
1.3 sizeof的参数可以是类型,也可以是变量,还可以是常量。对于相同类型,以上3中形式参数的sizeof返回值相同。
Cpp代码
int a;  
sizeof(a); // = 4  
sizeof(int); // = 4  
sizeof(1); // = 4
int a;
sizeof(a); // = 4
sizeof(int); // = 4
sizeof(1); // = 4


1.4 C99标准规定,函数、不能确定类型的表达式以及位域(bit-field)成员不能被计算s
izeof值,即下面这些写法都是错误的。
Cpp代码
void fn() { }  
sizeof(fn); // error:函数  
sizeof(fn()); // error:不能确定类型  
struct S  
{  
    int a : 3;  
};   
S sa;    
sizeof( sa.a ); // error:位域成员
void fn() { }
sizeof(fn); // error:函数
sizeof(fn()); // error:不能确定类型
struct S
{
int a : 3;
};
S sa;
sizeof( sa.a ); // error:位域成员

1.5 sizeof在编译阶段处理。由于sizeof不能被编译成机器码,所以sizeof的参数不能被编译,而是被替换成类型。
Cpp代码
int a = -1;  
sizeof(a=3); // = sizeof(a) = sizeof(int) = 4  
cout<<a<<endl; // 输出-1。由于“=”操作符返回左操作数的类型,赋值操作没有执行。
int a = -1;
sizeof(a=3); // = sizeof(a) = sizeof(int) = 4
cout<<a<<endl; // 输出-1。由于“=”操作符返回左操作数的类型,赋值操作没有执行。


2. 在32位系统中不同类型的内存分配
2.1 基本类型
Cpp代码
sizeof(int);        // = 4  
sizeof(double);     // = 8  
sizeof(char);       // = 1  
sizeof(bool);       // = 1  
sizeof(short);      // = 2  
sizeof(float);      // = 4  
sizeof(long);       // = 4
sizeof(int);        // = 4
sizeof(double);     // = 8
sizeof(char);       // = 1
sizeof(bool);       // = 1
sizeof(short);      // = 2
sizeof(float);      // = 4
sizeof(long);       // = 4

2.2 指针
指针在32位系统中占4个字节。
Cpp代码
sizeof(int *);         // = 4  
sizeof(double *);      // = 4  
sizeof(char *);        // = 4
sizeof(int *);         // = 4
sizeof(double *);      // = 4
sizeof(char *);        // = 4

2.3 数组
2.3.1 数组的sizeof返回整个数组所占的字节数,即(数组元素个数×每个元素所占字节)。
Cpp代码
int ai[] = {1, 2};  
sizeof(ai);          // = 2*4 = 8
int ai[] = {1, 2};
sizeof(ai);          // = 2*4 = 8


2.3.2 常量字符串与字符数组的内存分配方式相同。
Cpp代码
char ac[] = "abcd"; //注意数组末尾的字符串终结符'\0'  
sizeof(ac);          // = 5*1 = 5  
sizeof("abcd");      // = 5*1 = 5
char ac[] = "abcd"; //注意数组末尾的字符串终结符'\0'
sizeof(ac);          // = 5*1 = 5
sizeof("abcd");      // = 5*1 = 5


2.3.3 数组和指针所占的字节数不同,应注意区分。
Cpp代码
int *pi = new int[10]; //这是指针  
sizeof(pi);            // = 4  

int ai[10];  

int *p = ai;           //这还是指针  
sizeof(p);             // = 4  

double* (*a)[3][6];    //看成(double *) (*a)[3][6],即一个3×6的二维数组,数组元素为指针,指向double类型。  

sizeof(a);             // = 4,a为指向上述二维数组的指针  
sizeof(*a);            // = sizeof(double *)*3*6 = 72,*a表示上述二维数组      
sizeof(**a);           // = sizeof(double *)*6 = 24,**a即*(*a),表示double*[6],是元素为double指针的一维数组。  
sizeof(***a);          // = sizeof(double *) = 4,表示上述一维数组中的第一个元素,元素类型为double指针。  
sizeof(****a);         // = sizeof(double) = 8,表示上述数组首元素指向的double类型。
int *pi = new int[10]; //这是指针
sizeof(pi);            // = 4

int ai[10];
int *p = ai;           //这还是指针
sizeof(p);             // = 4

double* (*a)[3][6];    //看成(double *) (*a)[3][6],即一个3×6的二维数组,数组元素为指针,指向double类型。
sizeof(a);             // = 4,a为指向上述二维数组的指针
sizeof(*a);            // = sizeof(double *)*3*6 = 72,*a表示上述二维数组   
sizeof(**a);           // = sizeof(double *)*6 = 24,**a即*(*a),表示double*[6],是元素为double指针的一维数组。
sizeof(***a);          // = sizeof(double *) = 4,表示上述一维数组中的第一个元素,元素类型为double指针。
sizeof(****a);         // = sizeof(double) = 8,表示上述数组首元素指向的double类型。

2.3.4 函数形式参数中的数组会蜕变为指针,原因是数组参数“传址调用”,调用者只需将实参的地址传递过去。有一种情况例外,那就是参数是指向数组的指针。
Cpp代码
void acf(char p[3])     //参数类型是int[],表示指向int的指针  
{  
    sizeof( p );        // = 4  
}  
void aif(int p[])       //参数类型是int[],表示指向int的指针  
{  
    sizeof( p );        // = 4  
}  
void pif(int (*p)[6])   //参数类型是int (*)[6],表示指向int数组的指针  
{  
    sizeof( p);         // = 4  
    sizeof( *p );       // = sizeof(int)*6 = 24  
}  
void ppf(int *p[6])     //参数类型是int *[],表示指向int指针的指针  
{  
    sizeof( p );        // = 4  
    sizeof( *p );       // = 4  
}
void acf(char p[3])     //参数类型是int[],表示指向int的指针
{
    sizeof( p );        // = 4
}
void aif(int p[])       //参数类型是int[],表示指向int的指针
{
    sizeof( p );        // = 4
}
void pif(int (*p)[6])   //参数类型是int (*)[6],表示指向int数组的指针
{
    sizeof( p);         // = 4
    sizeof( *p );       // = sizeof(int)*6 = 24
}
void ppf(int *p[6])     //参数类型是int *[],表示指向int指针的指针
{
    sizeof( p );        // = 4
    sizeof( *p );       // = 4


2.4. 类和结构体的内存分配。
2.4.1 空类或空结构体占一个字节。
class CEmpty { };  
sizeof(CEmpty); // = 1  

struct SEmpty { };  

sizeof(SEmpty); // = 1
class CEmpty { };
sizeof(CEmpty); // = 1

struct SEmpty { };
sizeof(SEmpty); // = 1
2.4.2 非空类和结构体所占字节为所有成员占字节的和,但是不包括成员函数和静态成员所占的空间。
Cpp代码
class CInt : public CEmpty {  
    int i;  
};  
sizeof(CInt); // = 4;  

class CFunc {  

    void f() {}  
};  
sizeof(CFunc); // = 1;  

struct SInt : SEmpty {  

    static int i;  
};  
sizeof(SInt); // = 1;
class CInt : public CEmpty {
int i;
};
sizeof(CInt); // = 4;

class CFunc {
void f() {}
};
sizeof(CFunc); // = 1;

struct SInt : SEmpty {
static int i;
};
sizeof(SInt); // = 1;

2.4.3 字节对齐
为了加快计算机的取数速度,编译器默认对内存进行字节对齐。对结构体(包括类)进行字节对齐的原则是:
1)结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

2)结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);

3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

Cpp代码
struct SByte1  
{  
    double d;    // 偏移量0~7  
    char j;      // 偏移量8  
    int a;       // 偏移量12~15,由于9不能整除4,故先填充9~11  
};   
sizeof(SByte1); // = 16  

struct SByte2  

{        
    char j;      // 偏移量0  
    double d;    // 偏移量8~15,由于1不能整除8,故先填充1~7  
    int a;       // 偏移量16~19  
};   
sizeof(SByte2); // = 24,为了凑成8的倍数,填充20~23
struct SByte1
{
double d;    // 偏移量0~7
char j;      // 偏移量8
int a;       // 偏移量12~15,由于9不能整除4,故先填充9~11
};
sizeof(SByte1); // = 16

struct SByte2
{     
    char j;      // 偏移量0
double d;    // 偏移量8~15,由于1不能整除8,故先填充1~7
int a;       // 偏移量16~19
};
sizeof(SByte2); // = 24,为了凑成8的倍数,填充20~23

另外,可以通过#pragma pack(n)来设定变量以n字节对齐方式。
Cpp代码
#pragma pack(push) //保存对齐状态  
#pragma pack(4)    //设定为4字节对齐  
class CByte  
{  
    char c;        //偏移量0  
    double d;      //偏移量4~11,由于1不能整除4,故先填充1~3  
    int i;         //偏移量12~15  
};  
#pragma pack(pop) //恢复对齐状态  
sizeof(CByte); // = 16
#pragma pack(push) //保存对齐状态
#pragma pack(4)    //设定为4字节对齐
class CByte
{
char c;        //偏移量0
double d;      //偏移量4~11,由于1不能整除4,故先填充1~3
int i;         //偏移量12~15
};
#pragma pack(pop) //恢复对齐状态
sizeof(CByte); // = 16


2.4.4 位域
有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。


2.4.4.1 位域以比特位作为单位,其长度不能大于一个字节。一个位域必须存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。

Cpp代码
struct SBit1  
{  

    char a : 3;  
    char b : 4;  
    char c : 5;  
};  
sizeof(SBit1); // = (3+4+1+5+3) bits = 2 bytes
struct SBit1
{

    char a : 3;
    char b : 4;
    char c : 5;
};
sizeof(SBit1); // = (3+4+1+5+3) bits = 2 bytes
SBit1:| a × 3+ b × 4 + # × 1 | c × 5 + # × 3 |

2.4.4.2 使用空域可以有意使某位域从下一单元开始,但是空域不能使用。

Cpp代码
struct SBit2  
{  
    char a : 3;  
    char   : 0;   // 空域  
    char b : 4;  
    char c : 5;  
};  
sizeof(SBit2); // = (3+4+1+5+3) bits = 3 bytes
struct SBit2
{
    char a : 3;
    char   : 0;   // 空域
    char b : 4;
    char c : 5;
};
sizeof(SBit2); // = (3+4+1+5+3) bits = 3 bytes
SBit2:| a ×3 + # × 5 | b × 4 + # × 4 | c × 5 + # × 3 |

2.4.4.3 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式。
Cpp代码
struct SBit3  
{  
    char a : 3;  
    short b : 4;  
    char c : 5;  
};  
sizeof(SBit3); // = 6 bytes,由于相邻位域类型不同,在VC6中其sizeof为6,在Dev-C++中为2。
struct SBit3
{
    char a : 3;
    short b : 4;
    char c : 5;
};
sizeof(SBit3); // = 6 bytes,由于相邻位域类型不同,在VC6中其sizeof为6,在Dev-C++中为2。
SBit3(不压缩):| a ×3 | # ×8 |b × 4 + # ×4 | # ×8 | c ×5 + # ×3 | # ×8 |


SBit3(压缩):| a×3 + b ×4 + # ×1 |   c ×5 + # ×3 |

2.4.4.4 如果位域字段之间穿插着非位域字段,则不进行压缩。

Cpp代码
struct SBit4  
{  
    int a : 3;  
    int b : 4;  
    int c;  
};  
sizeof(SBit4); // = 8 bytes
struct SBit4
{
    int a : 3;
    int b : 4;
    int c;
};
sizeof(SBit4); // = 8 bytes

SBit4:| a×3 + b ×4 + # ×1 | # ×8 | # ×8 | # ×8 | c ×8 | c ×8 | c ×8 | c ×8 |

2.4.4.5 整个结构体的总大小为最宽基本类型成员大小的整数倍。

Cpp代码
struct SBit5  
{  
    int a : 3;  
    int b;  
    int c : 5;  
};  
sizeof(SBit5); // = 12 bytes
struct SBit5
{
    int a : 3;
    int b;
    int c : 5;
};
sizeof(SBit5); // = 12 bytes

SBit5:| a×3 + # ×5 | # ×8 | # ×8 | # ×8 | b ×8 | b ×8 | b ×8 | b ×8 | c ×5 + # ×3 | # ×8 | # ×8 | # ×8 |

2.5 联合
联合表示若干数据成员取其一,故以叠加方式分配内存,所占字节数为最大数据成员所占的字节数。
Cpp代码
union U  
{  
    int i;  
    char c;  
    double d;  
};  
sizeof(U); // = Max(sizeof(i), sizeof(c), sizeof(d)) = sizeof(d) = 8


<think>嗯,用户想了解如何在C/C++中使用sizeof来计数组的大小。首先,我需要回顾一下sizeof的基本用法。sizeof符可以返回对象或类型占用的字节数。对于数组来说,sizeof(数组名)应该返回整个数组的总字节数。例如,如果有一个int数组a,里面有5个元素,每个int占4字节,那么sizeof(a)应该是20字节。 然后,用户可能需要知道如何通过sizeof来计数组的元素个数。通常的做法是用整个数组的大小除以单个元素的大小,也就是sizeof(a)/sizeof(a[0])。这里要注意的是,数组名在作为sizeof的操作数时,不会退化成指针,所以能正确得到数组的总大小。这一点很重要,尤其是在处理数组作为函数参数的时候,因为此时数组会退化为指针,sizeof就无法正确得到数组大小了。例如,在函数内部使用sizeof(参数)的话,得到的只是指针的大小,而不是数组的大小。所以用户需要注意,这种方法只能在数组定义的同一作用域内使用。 接下来,我应该举一些例子来说明正确的用法。比如定义一个数组int a[5],用sizeof(a)得到总字节数,sizeof(a[0])得到每个元素的大小,然后相除得到元素个数5。还要指出常见的错误情况,比如当数组作为函数参数传递时,函数内部无法通过sizeof来计数组大小,这时候需要额外传递数组长度参数。 用户可能还会遇到多维数组的情况,这时候同样可以用sizeof来计。例如二维数组int b[3][4],总大小是sizeof(b),每个元素是sizeof(b[0][0]),总元素个数是sizeof(b)/sizeof(b[0][0])。或者计行数和列数,比如行数是sizeof(b)/sizeof(b[0]),列数是sizeof(b[0])/sizeof(b[0][0])。 需要注意的是,当数组是指针动态分配的时候,比如用malloc分配的数组,sizeof也无法正确计大小,因为此时变量实际上是一个指针,而不是数组类型。这时候用户必须自己记录数组的长度。 另外,用户提到的站内引用资料中提到数组作为参数传递时的问题,这点需要强调。比如引用[2]里说的,函数内使用sizeof(g)/sizeof(g[0])可能得到错误的结果,因为g已经退化为指针。所以正确的做法是在传递数组时,同时传递数组的长度参数,或者在数组定义的作用域内计好长度再传递。 最后,总结正确的使用步骤和注意事项,确保用户理解适用的场景和限制。可能还需要提醒用户,在C++中,可以考虑使用容器如std::array或std::vector来避免手动计长度的问题,但用户的问题明确是关于C/C++数组的,所以需要专注于原生的数组处理方法。</think>在C/C++中,使用`sizeof`运符计数组大小需注意作用域和数据类型特性,具体步骤如下: ### 一、基本原理 1. **数组总字节数**:`sizeof(数组名)`返回数组占用的总内存字节数,例如: ```c int a[5]; printf("%zu", sizeof(a)); // 输出20(假设int占4字节) ``` 2. **单个元素字节数**:`sizeof(数组名[0])`获取单个元素占用的字节数,例如: ```c printf("%zu", sizeof(a[0])); // 输出4 ``` 3. **元素数量计**:通过总字节数除以单个元素字节数: $$元素数量 = \frac{sizeof(数组名)}{sizeof(数组名[0])}$$ ```c int len = sizeof(a)/sizeof(a[0]); // 计结果为5 ``` ### 二、注意事项 1. **仅限原始作用域**:当数组作为函数参数传递时,会退化为指针,此时`sizeof(形参)`得到的是指针大小而非数组大小[^2]: ```c void func(int arr[]) { printf("%zu", sizeof(arr)); // 输出8(64位系统指针大小) } ``` 2. **动态分配数组不适用**:对`malloc`创建的数组,`sizeof`无法计实际长度: ```c int* dyn_arr = malloc(5 * sizeof(int)); printf("%zu", sizeof(dyn_arr)); // 输出指针大小(8字节) ``` 3. **多维数组计**: ```c int b[3][4]; int rows = sizeof(b)/sizeof(b[0]); // 计行数(3) int cols = sizeof(b[0])/sizeof(b[0][0]); // 计列数(4) ``` ### 三、代码示例 ```c #include <stdio.h> int main() { int arr[] = {1,2,3,4,5}; int length = sizeof(arr)/sizeof(arr[0]); // 正确计方式 printf("数组长度:%d", length); // 输出5 return 0; } ``` ### 四、应用场景对比 | 场景 | 可用性 | 原因说明 | |---------------------|--------|---------------------------| | 局部定义的静态数组 | ✅ | 保持完整数组类型信息 | | 函数参数传递的数组 | ❌ | 退化为指针 | | `malloc`动态数组 | ❌ | 本质是指针类型 | | 全局/静态存储区数组 | ✅ | 类型信息完整保留 |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值