C++ 中的 sizeof()

【牛客题目1】在Visual C++ 和 Mingw64平台上,short a[100], sizeof(a) 返回什么?

A. 2  B. 4  C. 100  D. 200  E. 400

答案:D 

Reference: https://www.nowcoder.com/test/question/done?tid=31013888&qid=1490#summary

解析:short int: 2个字节 【1.1】

sizeof 返回的数值表示的含义如下(单位字节)

  • 数组 - 编译时分配的数组空间大小 【1.1】(特别地,若数组作为参数被传入函数中做sizeof()运算,则和指针运算没区别)【1.2】
  • 指针 - 存储该指针所用的空间大小 (存储该指针的地址长度,是长整型,应该为4) 【2】
  • 类型 - 该类型所占用的空间大小 【3】
  • 对象 - 对象的实际占用空间大小 【4】
  • 函数 - 函数的返回类型所占的空间大小。函数的返回类型不能是void【5】

【题目2-13】

 1 char str[] = "Hello";
 2 char *p = str;
 3 int n = 10;
 4 sizeof(str) = 6;  // H,e,l,l,o,\0 [1.1]
 5 sizeof(p) = 4;    // [2]
 6 sizeof(n) = 4;    // [3]
 7 void Func(char str[10]){
 8     sizeof(str) = 4;      // [1.1]  
 9 }
10 void *p = malloc(100); 
11 sizeof(p) = 4;            // [2]

【题目2-14】使用sizeof()计算类对象所占空间大小, 结构体和类中的字符串对齐原则

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class A{
 5 public:
 6     int i;   //4
 7 };
 8 
 9 class B{
10 public:
11     char ch; //1
12 };
13 
14 class C{
15 public:
16     int i;    //4+1 ---> 对齐 4+4 = 8 
17     short j;
18 };
19 
20 class D{
21 public:
22     int i;    // 4+2+1 ---> 对齐 4+2+1+1 = 8
23     short j;
24     char ch;
25 };
26 
27 class E{
28 public:
29     int i;    // 4+4+2+1+1 = 12
30     int ii;
31     short j;
32     char ch;
33     char chr;
34 };
35 
36 class F{
37 public:
38     int i;    // 4+4+4+2+1+1 = 16
39     int ii;
40     int iii;
41     short j;
42     char ch;
43     char chr;
44 };
45 
46 int main(){
47     cout<<sizeof(A)<<' '<<sizeof(B)<<' '<<sizeof(C)<<' '<<sizeof(D)<<' '<<sizeof(E)<<' '<<sizeof(F)<<endl;
48 }

答案:4 1 8 8 12 16

为什么要字节对齐?一般情况下,如果不按照适合平台要求对数据存放进行对齐,会给存取效率带来损失。例如,有些平台每次读都是从偶地址开始,如果一个 int 型存放在偶地址开始的地方,那么一个读周期就可以读出;而如果存放在奇地址开始的地方,可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该 int 型数据。显然,在读取效率上下降很多。

字节对齐原则.

(1)结构体变量的首地址能够被其最宽基本类型成员的大小所整除

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

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

  【题目2-15】使用 sizeof() 计算含有虚函数的类对象的空间大小

#include <iostream>
using namespace std;

class Base{
public:
    Base(int x):a(x){}
    void print(){cout<<"base:"<<endl;}
private:
    int a;
};

class Derived:public Base{
public:
    Derived(int x):Base(x-1),b(x){}
    void print(){cout<<"derived"<<endl;}
private:
    int b;
};

class A{
public:
    A(int x):a(x){}
    virtual void print(){cout<<"A"<<endl;}
private:
    int a;
};

class B: public A{
public:
    B(int x):A(x-1),b(x){}
    virtual void print(){cout<<"B"<<endl;}
private:
    int b;
};

int main(){
    Base obj1(1);
    Derived obj2(2);
    A obj3(3);
    B obj4(4);
    cout<<sizeof(obj1)<<' '<<sizeof(obj2)<<' '<<sizeof(obj3)<<' '<<sizeof(obj4)<<endl;
    return 0;
}

答案: 4 8 8 12 

类的普通成员函数不占用内存,只有虚函数占用一个指针大小的内存,原因是系统多用一个指针维护这个类的虚函数表,并且注意这个虚函数无论含有多少项 (类中含有多少个虚函数)都不会再影响类的大小。

【题目2-16】使用sizeof()计算虚拟继承的类对象的空间大小

 1 #include<iostream>
 2 using namespace std;
 3 class A{};
 4 class B{};
 5 class C:public A, public B{};
 6 class D:virtual public A{};
 7 class E:virtual public A,virtual public B{};
 8 class F{
 9 public:
10     int a;
11     static int b;
12 };
13 int F::b = 10;
14 int main(){
15     cout<<sizeof(A)<<" "<<sizeof(B)<<" "<<sizeof(C)<<" "<<sizeof(D)<<" "<<sizeof(E)<<" "<<sizeof(F)<<endl;
16     return 0;
17 }

运行结果:1 1 1 4 8 4

Line 3, 4 -> A, B 是空类,编译器会安插一个 char 给空类,用来标记它的每一个对象。因此它的大小为1  

Line 5 -> 多类继承,大小为1

Line 6 -> 虚拟继承,编译器为该类安插一个指向父类的指针,编译器不会再安插 char,指针大小为4

Line 7 -> 虚拟继承 A和B, 有指向父类A和父类B的指针,加起来大小为8个字节

Line 8 -> F 含有一个静态成员变量,这个静态成员的空间不在类的实例中,而是像全局变量一样在静态存储区中,被每一个类的实例共享,因此其大小为 4 个字节。

【题目2-17】sizeof 与 strlen 有哪些区别

. sizeof 是操作符,strlen 是函数

. sizeof 操作符的结果是 size_t, 在头文件中用 typedef 为 unsigned int 类, 该类型保证能容纳实现所简历的最大对象的字节大小

. sizeof 可以用类型做参数, strlen 只能用 char* 做参数,且必须是以'\0'结尾的

. 数组做 sizeof 的参数不推户啊,传递给 strlen 就退化为指针了

. 大部分编译程序在编译的时候 sizeof 就被计算过了,这就是 sizeof() 可以用来定义数组维数的原因。strlen 的结果要在运行的时候才能计算出来,它用计算字符串的长度,不是类型占内存的大小

. 在字符串数组的长度上有差别, 如

1 char str[20]="0123456789";
2 int a = strlen(str); // 10 不包含 '\0'
3 int b = sizeof(str); // 20 数组大小
1 char *ss = "0123456789";
2 int a = sizeof(ss);  // 4 指针大小
3 int b = strlen(ss);  // 10 

【题目2-19】找错 - 使用 strlen() 函数代替 sizeof 计算字符串长度

 1 #include <iostream>
 2 #include <string.h>
 3 using namespace std;
 4 
 5 void UpperCase(char str[]){ 
 6     for(size_t i=0;i<sizeof(str)/sizeof(str[0]);++i){
 7         if('a'<=str[i] && str[i]<='z')
 8             str[i]-= ('a'-'A');
 9     }
10 }
11 
12 int main(){
13     char str[] = "aBcDe";
14     cout<<sizeof(str)/sizeof(str[0])<<endl;
15     UpperCase(str);
16     cout<<str<<endl;
17     return 0;
18 }

Line 5 函数作用,把小写字母换成大写, 但是 sizeof(str) = 4 因为 char str[] 作为形参,已退化为指针

LIne 14 中 sizeof(str)/sizeof(str[0]) 要比 strlen(str) 多1,存储 '\0'

因此,正确代码应该如下

 1 #include <iostream>
 2 #include <string.h>
 3 using namespace std;
 4 
 5 void UpperCase(char str[]){
 6     for(size_t i=0;i<strlen(str);++i){
 7         if('a'<=str[i] && str[i]<='z')
 8             str[i]-= ('a'-'A');
 9     }
10 }
11 
12 int main(){
13     char str[] = "aBcDe";
14     cout<<strlen(str)<<endl;
15     UpperCase(str);
16     cout<<str<<endl;
17     return 0;
18 }

【题目2-20】使用sizeof()计算联合体大小

 1 #include <iostream>
 2 using namespace std;
 3 
 4 union u{
 5     double a;
 6     int b;
 7 };
 8 
 9 union u2{
10     char a[13];
11     int b;
12 };
13 
14 union u3{
15     char a[13];
16     char b;
17 };
18 
19 int main(){
20     cout<<sizeof(u)<<' '<<sizeof(u2)<<' '<<sizeof(u2)<<endl;
21     return 0;
22 }

运行结果:8 16 13

联合体的大小取决于它所有的成员中占用最大的一个成员的大小。并且对于复合数据类型,如union, struct, class 的对齐方法是为成员中最大的成员对齐方式。如

对于 u 来说,大小就是最大的double 类型成员a了,sizeof(a)=8

对于u2来说,最大的空间是 char[13] 类型的数组。这里要注意,由于它的另一个成员 int b 的存在,u2 的对齐方式变成 4, 也就是说, u2 的大小必须在 4 的对齐上,所以占用的空间变为最接近 13 的 16。

对于 u3来说,最大的空间是 char[13] 类型的数组,即 sizeof(u3) = 13

【题目2-21】使用 #pragma pack 可以改变编译器对齐方式

 1 #include <iostream>
 2 #pragma pack(2)
 3 using namespace std;
 4 union u{
 5     char buf[9];
 6     int a;
 7 };
 8 
 9 int main(){
10     cout<<sizeof(u)<<endl;
11     return 0;
12 }

运行结果:10

使用 #pragma pack(x) 可以改变编译器的对齐方式。C++固有类型的对齐编译器与自身大小中较小的一个。

 1 #include <iostream>
 2 #pragma pack(1)
 3 using namespace std;
 4 struct test{
 5     char c;
 6     short s1;
 7     short s2;
 8     int i;
 9 };
10 
11 int main(){
12     cout<<sizeof(test)<<endl;
13     return 0;
14 }

运行结果:9

 

posted on 2020-03-07 02:54  猪伯  阅读(800)  评论(0编辑  收藏  举报

导航