sizeof运算符返回一条表达式(表达式结果类型的大小)或一个类型名字所占的字节数。
32位系统指针是4字节,64位系统指针是8字节
结构体
没有成员的结构体占用的空间是多少个字节?
答案是:1个字节。
这就是实例化的原因(空类同样可以被实例化),每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类或空结构体(C++中结构体也可看为类)隐含的加一个字节,这样空类或空结构体在实例化后在内存得到了独一无二的地址,所以空类所占的内存大小是1个字节。
sizeof求结构体大小的问题
https://www.bilibili.com/video/BV1be411x7ah?share_source=copy_web&vd_source=17cdeb76122f8dc86347b37ac29fd89d 看懂了
struct stu1 { int i; char c; int j; };
|
4 + 4 + 4 = 12
struct stu1 { int *i; int j; short c; };
|
12->16
struct s { int x: 3; int y: 4; int z: 5; double a; }
|
C语言的语法:位域。需要看清楚该结构体中是位操作,三个变量共占用一个int类型的大小,int类型占用4个字节,double占用8个字节。为了实现内存对齐,int类型需要填充4个字节的长度。前面补4位,4+4+8=16
答案16字节
结构体嵌套
typedef struct student4{ int id; double weight; float height; }Stu4;
|
结构体作为成员:如果一个结构体中同时包含结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储(如struct a中有struct b,而b中有char,int,double等元素,那么b应该从8(double类型的大小)的整数倍开始存储。
struct student5{ int id; double score; short grade; Stu4 aa; char name[2]; }Stu5;
|
2->4 + 1->4 + 4 + 4 = 16
struct stu5 { char i; struct { char c; int j; } ss; char a; char b; char d; char e; char f; }
|
1->4 + 1->4 + 4 + 5 = 17-> 20
联合体/共用体
https://codeantenna.com/a/V2wGOueu0U
长度为联合中元类型(如数组,取其类型的数据长度)最大的变量长度(对齐单位)的整数倍,且要大于等于其最大成员所占的存储空间。大于等于各种成员总长度,且为对齐单位的整数倍。
union foo{ int a; double d; }Foo1;
|
union foo{ char s[10]; int a; }Foo1;
|
union foo{ char s[10]; int a; double d; }Foo1;
|
2、联合体内嵌结构体
typedef struct student4{ int id; double weight; float height; }Stu4;
typedef union foo2{ Stu4 bb; char s[10]; int a; double d; }Foo2;
|
3、结构体内嵌联合体
struct student6{ char num[10]; int no[10]; Foo2 cc; char a; double a1; int a2; }Stu6;
|
枚举enum
1、enum只是定义了一个常量集合,里面没有“元素”,而枚举类型是当做int来存储的,所以枚举类型的sizeof值都为4。
enum Day
{
saturday,
sunday = 0,
monday,
tuesday,
wednesday,
thursday,
friday
} workday;
|
char数组
sizeof不是函数,仅仅是一个操作符
char char1[] = {'a', 'b'}; char char2[9] = {'c', 'd', 'e', 'f'}; char *char3 = (char *)"hello world"; string char4 = "this is a string.this is a string.this is a string.";
cout << "char1[] = {'a','b'} -> sizeof:" << sizeof(char1) << endl; cout << "char2[9] = {'c','d','e','f'} -> sizeof:" << sizeof(char2) << endl; cout << "char3 \"hello world\" -> sizeof:" << sizeof(char3) << endl; cout << "char4 string \"this is a string.\"-> sizeof:" << sizeof(char4) << endl; cout << endl; cout << "char1[10] = {'a','b'} -> strlen:" << strlen(char1) << endl; cout << "char2[9] = {'c','d','e','f'} -> strlen:" << strlen(char2) << endl; cout << "char3 \"hello world\" -> strlen:" << strlen(char3) << endl; cout << endl; cout << "char4 string \"this is a string.\"-> length:" << char4.length() << endl;
cout << "char4 string \"this is a string.\"-> size:" << char4.size() << endl;
char1[] = {'a','b'} -> sizeof:2 char2[9] = {'c','d','e','f'} -> sizeof:9 char3 "hello world" -> sizeof:8 char4 string "this is a string."-> sizeof:32
char1[10] = {'a','b'} -> strlen:2 char2[9] = {'c','d','e','f'} -> strlen:4 char3 "hello world" -> strlen:11
char4 string "this is a string."-> length:51 char4 string "this is a string."-> size:51
|
对于字符数组:sizeof得到的是字符数组的容量,strlen是的到的字符的长度
对于字符指针:sizeof得到的是指针的字节数8,strlen得到的是指针指向的字符的个数
对于string:sizeof得到的变量的字符大小32,而length和size得到的是变量中字符串的长度。
char buffer[] = "Hello"; int m = strlen(buffer); int n = sizeof(buffer);
|
以遇到的第一个’\0’为结束标志;n = 6,这是因为字符串以’\0’为结束标志,’\0’也需要占用一个字节,所以sizeof测得的结果为6。
所以char s[8] = “newcoder”是错的 需要s[9]
char str[100] = "abcdefg"; cout << sizeof(str) << endl; cout << sizeof(*str) << endl; cout << strlen(str) << endl;
char str1[] = "abcdefg"; cout << sizeof(str1) << endl; cout << strlen(str1) << endl;
char str2[] = "abcde0fg"; cout << sizeof(str2) << endl; cout << strlen(str2) << endl; char str3[] = "abcde\0fg"; cout << sizeof(str3) << endl; cout << strlen(str3) << endl;
char str4[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g'}; cout << sizeof(str4) << endl; cout << strlen(str4) << endl;
char str6[] = {'a', 'b', 'c', 'd', 'e', '0', 'f', 'g'}; cout << sizeof(str6) << endl; cout << strlen(str6) << endl;
char str7[] = {'a', 'b', 'c', 'd', 'e', '\0', 'f', 'g'}; cout << sizeof(str7) << endl; cout << strlen(str7) << endl;
char str8[] = {'a', 'b', 'c', 'd', 'e', 0, 'f', 'g'}; cout << sizeof(str8) << endl; cout << strlen(str8) << endl;
char str9[] = ""; cout << sizeof(str9) << endl; cout << strlen(str9) << endl; char a[10][9]; cout << sizeof(a) << endl;
|
#include <bits/stdc++.h> using namespace std; template <class T> int a(T) noexcept { return sizeof(T); }
template <class T> int b(T &&) noexcept { return sizeof(T); }
int f(char a[]) { return sizeof(a); }
int main(int argc, char *argv[]) { int i = 123; int aa[100] = {i}; int *p = aa; cout << a(i) << endl << a(aa) << endl << a(p) << endl; cout << b(i) << endl << b(aa) << endl << b(p) << endl; cout << sizeof(i) << endl << sizeof(aa) << endl << sizeof(p) << endl; char aaa[15]; cout << sizeof(aaa) << endl << f(aaa) << endl; system("pause"); return 0; }
|
类对象
计算需要考虑成员变量大小,内存对齐,是否有虚函数,是否有虚继承等
- 空类
#include <iostream> using namespace std; class A { }; class B : public A{ }; class C : public B{ }; int main() { A a; B b; C c; cout<<"size of a:"<<sizeof(a)<<endl; cout<<"size of b:"<<sizeof(b)<<endl; cout<<"size of c:"<<sizeof(c)<<endl; return 0; }
|
仅有常规函数、无成员变量类
扩展1:如果在该类型中添加一个构造函数和析构函数,再求sizeof,得到的结果是多少?
答案:还是1。调用构造函数和析构函数只需要知道函数的地址即可,而这些地址只与类型相关,而与类型的实例无关, 编译器也不会因为这两个函数而在实例内添加任何额外的信息。
注:不管添加的是构造函数还是析构函数还是其它任何类型的函数,都是这个结果。
#include <iostream> using namespace std; class A { public: A(int x=0) { cout<<"A"<<x<<endl; } void printA() { cout<<"Hello A"; } }; class B :public A{ public: B(int x=0) { cout<<"B"<<x<<endl; } void printB() { cout<<"Hello B"; } }; class C : public B{ public: C() { cout<<"C"<<endl; } void printC() { cout<<"Hello C"; } }; int main() { A a; B b; C c; cout<<"size of a:"<<sizeof(a)<<endl; cout<<"size of b:"<<sizeof(b)<<endl; cout<<"size of c:"<<sizeof(c)<<endl; return 0; }
|
仅包含一般成员函数(即没有虚函数),不含成员变量时,运行结果和(一)是一样的,系统也只是为对象创建了1个字节的占位符。因此,我们可以得出结论是,一般成员函数不会对类的大小造成影响。
含有一般成员变量类
普通的继承就是基类的大小+派生类自身的大小。
#include <iostream> using namespace std; class A { public: A(int x=0) { cout<<"A"<<x<<endl; } void printA() { cout<<"Hello A"; } private: char Data1[3]; int Data2; }; class B :public A{ public: B(int x=0) { cout<<"B"<<x<<endl; } void printB() { cout<<"Hello B"; } private: char Data1[3]; int Data2; }; class C : public B{ public: C(int x=0) { cout<<"C"<<x<<endl; } void printC() { cout<<"Hello C"; } private: char Data1[3]; int Data2; }; int main() { A a; B b; C c; cout<<"size of a:"<<sizeof(a)<<endl; cout<<"size of b:"<<sizeof(b)<<endl; cout<<"size of c:"<<sizeof(c)<<endl; return 0; }
|
依次继承的三个类中含有相同数量,相同类型的一般成员变量(不含静态成员变量)。此种情况下,类对象大小=基类对象大小+自身成员大小。A当中三个字符变量3个字节,一个整形变量4个字节,考虑内存对齐因素(默认为4),A类对象大小为8。B类对象大小为A类对象大小基础上再加8,C类对象大小在B类对象大小基础上再加8。
- 含静态成员变量的类
#include <iostream> using namespace std; class A { public: A(int x=0) { cout<<"A"<<x<<endl; } void printA() { cout<<"Hello A"; } private: char Data1[3]; int Data2; static int Data3; }; class B: public A { public: B(int x=0) { cout<<"B"<<x<<endl; } void printB() { cout<<"Hello B"; } private: char Data1[3]; int Data2; static int Data3; }; class C : public B{ public: C(int x=0) { cout<<"C"<<x<<endl; } void printC() { cout<<"Hello C"; } private: char Data1[3]; int Data2; static int Data3; }; int main() { A a; B b; C c; cout<<"size of a:"<<sizeof(a)<<endl; cout<<"size of b:"<<sizeof(b)<<endl; cout<<"size of c:"<<sizeof(c)<<endl; return 0; }
|
可以看到,类对象大小没有因为增加了静态成员而变化。因为静态成员是属于类成员共有的,不单独属于任何一个对象,对静态成员的存储不会选择在某个对象空间,而是存在于堆当中,因此不会对对象的大小造成影响。
- 虚函数
using namespace std; class A { public: virtual void fun(){}; }; class B { public: virtual void fun(){}; virtual void fun1(){}; virtual void fun2(){}; }; int main() { A a; B b; cout << sizeof(a) << endl; cout << sizeof(A) << endl; cout << sizeof(B) << endl; system("pause"); return 0; }
|
class A { public: char b; double a; short c; }; class B { public: char a; virtual void fun() {} short b; }; int main() { cout << sizeof(A) << endl; cout << sizeof(B) << endl; system("pause"); return 0; }
|
为了效率问题,编译器(gcc 和 微软)一般会把虚指针放在类的内存空间的最前面的位置,不管虚函数声明的位置。考虑对齐,大小都是 4 +1+1+2 = 8.
class A { virtual void fun() {} }; class B : public A { public: virtual void fun2() {} }; class C : virtual public A { public: virtual void fun3() {} }; int main() { cout << sizeof(A) << endl; cout << sizeof(B) << endl; cout << sizeof(C) << endl; system("pause"); return 0; }
|
派生类继承了基类的虚指针,所以大小为4。
其他
vector<int> ivec; cout << sizeof(ivec) << endl; 3个指针 = 24
|