Last Updated: 2023-12-12 04:52:35 Tuesday
-- TOC --
sizeof是C语言的一种编译期执行的单目操作符(unary operator),它并不是函数。sizeof操作符以字节形式给出了其操作数(operand)的存储大小,返回值类型为size_t。
sizeof操作数可以是一个表达式或类型名,操作数的存储大小由操作数的类型决定。
$ cat test.c
#include <stdio.h>
int main(void) {
printf("sizeof(size_t):%zu\n", sizeof(size_t));
return 0;
}
$ gcc test.c -o test
$ ./test
sizeof(size_t):8
sizeof返回size_t,打印size_t类型,使用%zu
,C99。
sizeof后面不一定要使用括号,如果是一个变量,可以不用括号,如下。不过,一般我们都会使用统一使用括号!
int a = 0;
int sizeofa = sizeof a;
注意:sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。如sizeof(max),若此时变量max定义为int max(),或sizeof(char_v),若char_v定义为char char_v[MAX],且MAX未知,或sizeof(void),都不是正确形式。
sizeof一个变量,而不是sizeof这个变量的type,可以让代码更具可维护性。
这是一个很common的trick,用sizeof获取数组的长度:
int aa[] = {1,2,3,4,5,6,7,8};
printf("%d\n", sizeof(aa)/sizeof(int));
sizeof(aa)能够正确得到整个数组所占用的byte数,aa的类型为int []
,其size在编译期可以确定。
获取variadic template parameter的个数。
我们在提到字节对齐的时候,一般都是在说结构体struct所占用的那块内存。
$ cat test.c
#include <stdio.h>
struct char_double{
char c;
double d;
};
typedef struct char_double cd;
int main(void) {
char *p = NULL;
printf("sizeof(pointer):%zu\n", sizeof(p));
printf("sizeof(cd):%zu\n", sizeof(cd));
return 0;
}
$ gcc test.c -o test
$ ./test
sizeof(pointer):8
sizeof(cd):16
结构体实际上只使用了9个byte,但是sizeof的结果是16,这就是字节对齐!字节对齐是为了提高代码访问内存的效率,但同时也可能会造成一些潜在的问题,特别是在网络编程处理报文的时候。
下面是关于gcc中如何设置结构体字节对齐的测试代码,同时也展示了sizeof的使用:
$ cat test.c
#include <stdio.h>
typedef struct test0{
char c;
double d;
} test0;
typedef struct test1{
char c;
double d;
} __attribute__((aligned(4))) test1;
typedef struct test2{
char c;
double d;
} __attribute__((packed)) test2;
typedef struct test3{
char c;
double d;
} __attribute__((aligned(16))) test3;
typedef struct aa{
char a;
char b;
} aa;
int main(void) {
printf("sizeof(test0):%zu\n", sizeof(test0));
printf("sizeof(test1):%zu\n", sizeof(test1));
printf("sizeof(test2):%zu\n", sizeof(test2));
printf("sizeof(test3):%zu\n", sizeof(test3));
printf("sizeof(aa):%zu\n", sizeof(aa));
return 0;
}
$ gcc test.c -o test
$ ./test
sizeof(test0):16
sizeof(test1):16
sizeof(test2):9
sizeof(test3):16
sizeof(aa):2
aligned(n)表示以n字节的方式对齐,n必须为power of 2,packed表示1字节对齐!
注意最后那个sizeof(aa),大小为2,不是8!!
节省内存的struct设计细节:一般情况下,在定义结构体的时候,内部成员建议按照从大到小的顺序书写,成员申明的顺序,也是它们在内存中布局的顺序,从大到小有利于节省内存。但这个规则并不绝对,在定义struct时,最好人工check一下最优的顺序是什么,原则就是尽量减少元素之间为了字节对齐而产生的padding。
规则一:结构体中元素是按照定义顺序一个个放到内存中的,但默认并非紧密排列。从结构体的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己大小的整数倍上开始(以结构体变量首地址为0计算)。
typedef struct AA{
char a;
char a2;
int b;
double c;
}AA;
// sizeof(AA) == 16
// a
// a2
//
//
// b
// b
// b
// b
// c
// c
// c
// c
// c
// c
// c
// c
规则二:在按照第一规则进行内存分配后,需要检查计算分配的内存大小是否为所有成员中size最大成员的size的整数倍,若不是,则补齐为它的整数倍。
typedef struct BB{
char a;
char a2;
double b;
int c;
}BB;
// sizeof(BB) == 24
// a
// a2
//
//
//
//
//
//
// b
// b
// b
// b
// b
// b
// b
// b
// c
// c
// c
// c
//
//
//
//
规则三:当存在结构体嵌套时,以上两条规则依然成立,只是size最大的成员,要在所有内嵌结构体的成员中确认。
typedef struct xyz{
char a;
int b;
struct AA{
long int x;
char y;
} aa;
short c;
}xyz;
// sizeof(xyz) == 32
size最大的成员是内嵌结构体中的x,为8,因此要执行8字节对齐。同时,嵌套的struct AA要形成一个boundary,因此最后的sizeof值为32。
typedef struct xyz{
char a;
int b;
struct AA{
int x;
char y;
struct BB{
long int z;
} bb;
} aa;
char c;
}xyz;
// sizeof(xyz) == 32
按照bb中的z的size对齐。
#include <iostream>
using namespace std;
struct alignas(64) xyz {
char a;
int b;
};
int main(void) {
cout << sizeof(xyz) << endl;
return 0;
}
输出:64
alignas关键词是C++11引入的,是一种可以跨平台的申明字节对齐的方式,最小有效值为8。
#include <iostream>
#include <cstdio>
#include <string>
#include <unordered_map>
using namespace std;
struct xyz{
int a;
char b;
string c;
int d;
unordered_map<int,int> e;
char f;
};
int main(){
xyz x;
cout << "sizeof(xyz) = " << sizeof(xyz) << endl;
printf("%p\n", &x.a);
printf("%p\n", &x.b);
printf("%p\n", &x.c);
printf("%p\n", &x.d);
printf("%p\n", &x.e);
printf("%p\n", &x.f);
return 0;
}
结构体xyz包含一个string对象和一个unordered_map对象,这些对象的定义,也是一个class或struct,sizeof和字节对齐的规则,应该与结构体嵌套一样。
输出:
sizeof(xyz) = 112
0x7ffe29dc0b80
0x7ffe29dc0b84
0x7ffe29dc0b88
0x7ffe29dc0ba8
0x7ffe29dc0bb0
0x7ffe29dc0be8
整体是4字节对齐。
class的static成员的存储区域,与其它成员不一样,因此static成员不占sizeof大小。更多:在C++的类中使用static申明
与static成员一样,不占sizeof大小。
本文链接:https://cs.pynote.net/sf/c/202111197/
-- EOF --
-- MORE --