C++ 中的 sizeof()

你说的曾经没有我的故事 提交于 2020-03-07 04:07:02

【牛客题目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 个字节。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!