数据类型及指针大小
最近写代码,内存分配不管二级还是一级全放在一起申请,导致各种地址偏移,转换。这里记录几个常见的数据的大小
#include <iostream>
#include <stdint.h>
int main() {
std::cout << "void** :" << sizeof(void**) << std::endl;
std::cout << "void* :" << sizeof(void*) << std::endl;
std::cout << "int** :" << sizeof(int**) << std::endl;
std::cout << "int* :" << sizeof(int*) << std::endl;
std::cout << "int :" << sizeof(int) << std::endl;
std::cout << "uint8_t* :" << sizeof(uint8_t*) << std::endl;
std::cout << "uint8_t :" << sizeof(uint8_t) << std::endl;
std::cout << "char :" << sizeof(char) << std::endl;
return 0;
}
实验
我打算申请这样一块地址
/* ------- 4 * int --------- 2 * (int *) -------- (int **) --- */
/* ----------16------------------16------------------8-------- */
int size = 4 * sizeof(int) + 2 * sizeof(int *) + sizeof(int **);
void* ptr = new uint8_t[size];
void* ptr_bak = new uint8_t[size];
delete[] static_cast<uint8_t*>(ptr);
delete[] static_cast<uint8_t*>(ptr_bak);
前4个int大小的放四个int数据, 中间2个int* 大小的将前4个int 分成2个int* 的地址存放,最后一个int**,放前两个int*的地址。
int* int_ptr = reinterpret_cast<int *>(ptr);
int_ptr[0] = 0;
int_ptr[1] = 1;
int_ptr[2] = 2;
int_ptr[3] = 3;
int test = *(static_cast<int*>(ptr) + 1);
std::cout << "test : " << test << std:: endl;
这里ptr是用new uint8_t
申请的,而一个uint8_t是1。返回的是uint8_t*
。那么当前的ptr是一个大小为40的uint8_t的数组。
同理我将uint8_t*
的指针转成int*
的指针,那么int_ptr 就类似表示为大小为8的int数组。我对ptr数组的前四个,分别赋值为0,1,2,3.
int test = *(static_cast<int*>(ptr) + 1);
这行的意思就是先将ptr转换成int*
的指针,那么实际的每个元素就是一个int,那么+1
的意思就是加1个int的偏移。
最外层的*
就是解引用,将int_ptr[1]的值取出来。这里一定要小心,不要以为int为四个字节,就需要加上4.
所以上面的打印结果就是1.
接下来我们将前面的4个int,分为两组,然将这个两个值赋值给后面的两个``int*```
int** int_s_ptr = reinterpret_cast<int**>(static_cast<int**>(ptr) + 2);
int_s_ptr[0] = &int_ptr[0];
int_s_ptr[1] = &int_ptr[2];
这里怎么看这段代码呢?首先我们把ptr想成里面放int*
的数据,那么对于这些地址的地址就是一个int**
的存在,
那么我们就应该先static_cast<int**>, 然后偏移两个int*
,找到实际的int*
,存放的地址。
在接下来我们将2个int*
的地址放入最后一个int**
中。
int*** int_ss_ptr = reinterpret_cast<int***>(static_cast<int***>(ptr) + 4);
int_ss_ptr[0] = &int_s_ptr[0];
对于最后一个应该放int**
,那么该地址的指针就是int***
的,然后就是前面偏4个int和2个int*
,就是偏4个int**
最后我们验证下结果,将数组拷贝到ptr_bak中测试
#include <cstring>
#include <iostream>
#include <stdint.h>
int main(int argc, char **argv) {
/* ------- 4 * int --------- 2 * (int *) -------- (int **) --- */
/* ----------16------------------16------------------8-------- */
int size = 4 * sizeof(int) + 2 * sizeof(int *) + sizeof(int **);
void *ptr = new uint8_t[size];
void *ptr_bak = new uint8_t[size];
int *int_ptr = reinterpret_cast<int *>(ptr);
int_ptr[0] = 0;
int_ptr[1] = 1;
int_ptr[2] = 2;
int_ptr[3] = 3;
int test = *(static_cast<int *>(ptr) + 1);
std::cout << "test : " << test << std::endl;
int **int_s_ptr = reinterpret_cast<int **>(static_cast<int **>(ptr) + 2);
int_s_ptr[0] = &int_ptr[0];
int_s_ptr[1] = &int_ptr[2];
int ***int_ss_ptr = reinterpret_cast<int ***>(static_cast<int ***>(ptr) + 4);
int_ss_ptr[0] = int_s_ptr;
memcpy(ptr_bak, ptr, sizeof(uint8_t) * size);
int ***test_ptr =
reinterpret_cast<int ***>(static_cast<int ***>(ptr_bak) + 4);
std::cout << "test_ptr[0][0][0] = " << test_ptr[0][0][0] << std::endl;
std::cout << "test_ptr[0][0][1] = " << test_ptr[0][0][1] << std::endl;
int **test_s_ptr = test_ptr[0];
int *tt = test_s_ptr[1];
std::cout << "test_ptr[0][1][0] = " << test_ptr[0][1][0] << std::endl;
std::cout << "test_ptr[0][1][1] = " << test_ptr[0][1][1] << std::endl;
delete[] static_cast<uint8_t *>(ptr);
delete[] static_cast<uint8_t *>(ptr_bak);
return 0;
}
运行结果
这里有个小技巧,就是申请这些地址,不知道到底应该当成什么地址看,那么可以直接将申请的的地址当成char* 或者uint8_t*之类的,这时候其实加1就是加1个字节的偏移,然后偏移好后
使用reinterpret_cast转成自己想要的地址就好了。
还有就是&[0]
其实就是首地址,我这只是方便阅读而已。