标签:
该问题值得探讨!
先贴自己的测试代码、反汇编以及内存转储图(测试环境:CodeBlocks、编译器GCC、系统64位)
【分别测试了数组大小为3和5的情况】
从内存转储可以看到,GCC其实并不是像网友说的那样,通过指针偏移、额外开辟8字节空间来存储长度。
具体是怎么做到的,目前我也不知道。有待探讨。
【下面贴出几个在知乎上看到的我觉得值得一看的回答】
“嗯,是这样的,内存管理库里总会有一个方法来记录你分配的内存是多大,你写的"在 p 地址之前有一个 n 记录这个数组的大小"是一种实现方法,管理库当然也可以自己维护一个列表,记录所有空间分配的位置和大小以及类型,delete的时候查一下这个列表就行了,也就是所谓"不是所有的编译器都是非这么实现不可",目前来说,常见的C++编译器也就是GCC/VCC/ICC/BCC等,具体实现可以查各编译器的文档说明,当然商业编译器不一定肯说.
#include<cstdio>
#include<iostream>
#include<malloc.h>
#include<assert.h>
#include<ctime>
using namespace std;
#define size 16
int main(void)
{
void * p = NULL;
srand(time(0));
int a = 10;
while (a--)
{
int n = rand() % 10000;
p = malloc(n);
size_t w = *((size_t*)((char*)p - size));
cout << "w=" << w << endl;
cout << "n=" << n << endl;
assert(w == n);
free(p);
}
return 0;
}
//这儿是根据不同的硬件平台的宏定义
#if defined (_M_IX86)
#define _ALLOCA_S_MARKER_SIZE 8
#elif defined (_M_X64)
#define _ALLOCA_S_MARKER_SIZE 16
#elif defined (_M_ARM)
#define _ALLOCA_S_MARKER_SIZE 8
#elif !defined (RC_INVOKED)
#error Unsupported target platform.
#endif /* !defined (RC_INVOKED) */
_STATIC_ASSERT(sizeof(unsigned int) <= _ALLOCA_S_MARKER_SIZE);
#if !defined (__midl) && !defined (RC_INVOKED)
#pragma warning(push)
#pragma warning(disable:6540)
__inline void *_MarkAllocaS(_Out_opt_ __crt_typefix(unsigned int*) void *_Ptr, unsigned int _Marker)
{
if (_Ptr)
{
*((unsigned int*)_Ptr) = _Marker;
//
_Ptr = (char*)_Ptr + _ALLOCA_S_MARKER_SIZE;
//最后返回给调用者的指针,是原始指针偏移了_ALLOCA_S_MARKER_SIZE的新指针,这也是刚才我将指针向后偏移,就能得到该指针所指向内存区块的大小的原因。
}
return _Ptr;
}
/* _freea must be in the header so that its allocator matches _malloca */
#if !defined (__midl) && !defined (RC_INVOKED)
#if !(defined (_DEBUG) && defined (_CRTDBG_MAP_ALLOC))
#undef _freea
__pragma(warning(push))
__pragma(warning(disable: 6014))
_CRTNOALIAS __inline void __CRTDECL _freea(_Pre_maybenull_ _Post_invalid_ void * _Memory)
{
unsigned int _Marker;
if (_Memory)
{
_Memory = (char*)_Memory - _ALLOCA_S_MARKER_SIZE;
//获得原始指针
_Marker = *(unsigned int *)_Memory;//得到指针所指区块的大小
if (_Marker == _ALLOCA_S_HEAP_MARKER)
{
free(_Memory);
}
#if defined (_ASSERTE)
else if (_Marker != _ALLOCA_S_STACK_MARKER)
{
#pragma warning(suppress: 4548) /* expression before comma has no effect */
_ASSERTE(("Corrupted pointer passed to _freea", 0));
}
#endif /* defined (_ASSERTE) */
}
}
// Allocator adaptor to check size arguments for debugging.
// Reports errors using assert. Checking can be disabled with
// NDEBUG, but it‘s far better to just use the underlying allocator
// instead when no checking is desired.
// There is some evidence that this can confuse Purify.
template <class _Alloc>
class debug_alloc {
private:
enum {_S_extra = 8}; // Size of space used to store size. Note
// that this must be large enough to preserve
// alignment.
//这儿就像它所说的那样
public:
static void* allocate(size_t __n)
{
//
这里实际申请的内存大小要多 8 个字节
char* __result = (char*)_Alloc::allocate(__n + (int) _S_extra);
*(size_t*)__result = __n;//前 4 个字节用于存储区块大小,可以看到,它预留了4个字节的空白区,具体原由 还望大牛能指出,==。
return __result + (int) _S_extra;//最后返回相对于原始指针偏移8个字节的新指针
}
static void deallocate(void* __p, size_t __n)
{
char* __real_p = (char*)__p - (int) _S_extra;//获得原始指针
assert(*(size_t*)__real_p == __n);//这里增加了一个断言,防止析构了被破坏的指针
_Alloc::deallocate(__real_p, __n + (int) _S_extra);
}
static void* reallocate(void* __p, size_t __old_sz, size_t __new_sz)
{
char* __real_p = (char*)__p - (int) _S_extra;
assert(*(size_t*)__real_p == __old_sz);
char* __result = (char*)
_Alloc::reallocate(__real_p, __old_sz + (int) _S_extra,
__new_sz + (int) _S_extra);
*(size_t*)__result = __new_sz;
return __result + (int) _S_extra;
}
};
#if(defined(_X86_) && !defined(__x86_64))
#define _ALLOCA_S_MARKER_SIZE 8
#elif defined(__ia64__) || defined(__x86_64)
#define _ALLOCA_S_MARKER_SIZE 16
#endif
#if !defined(RC_INVOKED)
static __inline void *_MarkAllocaS(void *_Ptr,unsigned int _Marker) {
if(_Ptr) {
*((unsigned int*)_Ptr) = _Marker;
_Ptr = (char*)_Ptr + _ALLOCA_S_MARKER_SIZE;
}
return _Ptr;
}
#endif
#ifndef RC_INVOKED
#undef _freea
static __inline void __cdecl _freea(void *_Memory) {
unsigned int _Marker;
if(_Memory) {
_Memory = (char*)_Memory - _ALLOCA_S_MARKER_SIZE;
_Marker = *(unsigned int *)_Memory;
if(_Marker==_ALLOCA_S_HEAP_MARKER) {
free(_Memory);
}
#ifdef _ASSERTE
else if(_Marker!=_ALLOCA_S_STACK_MARKER) {
_ASSERTE(("Corrupted pointer passed to _freea",0));
}
#endif
}
}
#endif /* RC_INVOKED */
标签:
原文地址:http://blog.csdn.net/chenyyhh92/article/details/51168071