字节对齐,sizeof,strlen,_countof,offsetof,_msize

一、sizeof

sizeof()返回值最好用size_t保存,在x86和x64下,该类型有不同的表示,unsigned int(32位),unsigned __int64(64位)

#include <iostream>
#include <string>
#include <vector>

int main()
{   
    int arrx[20];
    auto n = _countof(arrx);  //n = 20,返回值类型为unsigned int 宏_countf定义在stdlib.h,c++包含vector头文件也可以使用
    
    //sizeof返回值的类型是size_t,unsigned int(32位),unsigned __int64(64位)
    char ch1[] = "HelloWorld";
    char* ch2 = ch1;   //sizeof(ch2)
    int arr1[] = { 1,2,3,4,5,6,7 };
    int* arr2 = arr1;
    std::string str1 = "HelloC++";
    std::string str2;

    size_t s1 = sizeof(ch1);  //11,"HelloWorld\0"因为是内存占用的空间大小,所以包含最后的字符串结束符号\0,所以是10+1=11
    size_t s2 = sizeof(ch2);  //和编译器平台有关,sizeof(ch2)得到的是指针的大小,x64为8,x86为4
    size_t s3 = sizeof(str1); //sizeof(str)得到的是string对象的大小,是一个固定值,和str具体内容无关
    size_t s4 = sizeof(str2); //64位:40,32位:28
    size_t s5 = sizeof(arr1); //28   一个int占4个字节,7*4=28
    size_t s6 = sizeof(arr2); //指针的大小,和编译器平台有关,32位:4,64位:8

    size_t s01 = sizeof((*ch1));  //1
    size_t s02 = sizeof((*ch2));  //1
    size_t s03 = sizeof((*arr1)); //4
    size_t s04 = sizeof((*arr2)); //4 解引用得到的都是第一个元素类型的大小 char:1,int:4

    size_t s7 = str1.length();//8,字符串的长度,有几个字符就是几,不包含字符串结束符\0
    size_t s8 = strlen(ch1);  //10,strlen(str1)错误,strlen的参数为const char*,字符串的长度,有几个字符就是几
    size_t s9 = str1.size();  //8,同str.length(),size还可用于获取容器的大小

    std::vector<std::string> vec;
    vec.emplace_back("abcdef");
    vec.emplace_back("123");
    vec.emplace_back("qwert");
    size_t s10 = vec.size();   //3
    size_t s11 = sizeof(vec);  //和元素的个数无关,64位:32,32位:16,应该是存放了四个指针(不确定)
    size_t s12 = sizeof(std::vector<bool>); //bool比其他类型大1/2,即64:48,32:24,
    size_t s13 = sizeof(std::vector<int>);  //16,32
    size_t s14 = sizeof(std::vector<std::string>);  //16,32
    size_t s15 = sizeof(std::vector<char>); //16,32

    return 0;
}

二、字节对齐

#include <iostream>

int main()
{
    struct s1  //16
    {
        int i;
        char c;
        double d;
    };
    struct s2   //16
    {
        double d;
        char c;
        int i;
    };
    struct s3  //16
    {
        char c;
        int i;
        double d;
    };
    struct s4  //24
    {//结构体中占用空间最大的类型为8(double),1+7 + 8 + 4 = 20 不是8的倍数,所以要填充4个字节,满足sizeof(double)=8的倍数
        char c;
        double d;
        int i;
    };
    std::cout << sizeof(s1) << sizeof(s2) << sizeof(s3) << sizeof(s4) << std::endl;
#pragma pack(push) //保存对齐状态    push和pop是一对,不用push和pop包住,pack(n)将会对后面的所有sizeof生效
#pragma pack(4)    //设定为4字节对齐
    struct t1
    {
        char m1;
        double m4;
        int  m3;
    };
    std::cout << sizeof(t1) << std::endl;  //16
#pragma pack(pop)//恢复对齐状态
    struct t2
    {
        char m1;
        double m4;
        int  m3;
    };
    std::cout << sizeof(t2) << std::endl;  //24

    return 0;
}

三、字符串长度

cstring头文件(C风格字符串)

strlen(str)计算字符串长度(有几个字符就返回几,不包含末尾的'\0')

string头文件(std::string)

str.size()返回字符串的长度(包括结尾的空字符,即空格也算,string类型的字符串结尾没有'\0')

CString头文件(MFC)

str.GetLength()返回的是字符个数(不包括结尾的空字符)

四、sizeof(常见类型)

1.sizeof(std::string)

转载:string在内存中的布局

名称 X86(字节数) X64(字节数)
Allocator 4 8
原始字符串Data位置 15 + 1,最多包含15个字符加一个结束符'\0' 15 + 1,最多包含15个字符加一个结束符'\0'
字符长度Size 4 8
当前容量Capacity 4 8
总计 28 40

以下我们只讨论 32位程序

  • 对于长度小于等于15个字符的字符串:

数据会保存到Data的总计16个字节中,如果string 是临时变量,整个字符串的数据位于栈上

  • 对于数据大于15个字符的字符串:

会在堆上分配一块额外的数据区域,并将所有数据填充到堆中,然后将堆指针赋值到 Data 的第一个指针位置 (Data前4个字节)

2.sizeof(容器)

容器 x64 x86
deque 40 20
vector 32 16

3.sizeof(class)

class X{};
class Y : public virtual X {};
class Z : public virtual X {};
class A : public Y,public Z {};

sizeof(X) //1
sizeof(Y) //4
sizeof(Z) //4
sizeof(A) //8

X为1是因为编译器的处理,在其中插入了1个char,为了让其对象能在内存中有自己独立的地址Y,Z是因为虚基类表的指针A 中含有Y和Z所以是8

五、一些用来获取字节数或元素个数的方法

_countof

windows宏,用来计算一个静态分配的数组中的元素的个数,返回值的类型为 unsigned int ,必须是静态分配的数组,不能是指针

	char s1[] = "12345";
	int s2[] = { 1,2,3,4,5 };
	int* s3 = new int[10]();

	auto ret1 = _countof(s1);  //6,包含'\0'
	auto ret2 = _countof(s2);  //5
	//auto ret3 = _countof(s3); //error

offsetof

offsetof 会生成一个类型为size_t的整型常量,它是一个结构成员相对于结构开头的字节偏移量。成员是由 member-designator 给定的,结构的名称是在type 中给定的。

_msize

获取指针指向内容的实际大小(不是指针的大小),只能获取到new或malloc出来的指针指向内容的大小。

#include <iostream>

void fun(int* p)
{
	std::cout << sizeof(p) << '\n';  //8  (x64)
	std::cout << _msize(p) << '\n';  //40 = 4*10
}

int main()
{
	int* p = new int[10]();
	int p1[] = { 1,2,3 };

	fun(p);
	//fun(p1);  //不是new或malloc出来的指针,程序会崩溃

	return 0;
}
posted @ 2020-12-04 23:48  滴哒哒哒  阅读(134)  评论(0编辑  收藏  举报