可能重复:
How can I get the size of an array from a pointer in C?
Is there any way to determine the size of a C++ array programmatically? And if not, why?
我从C样式函数中获取指向一块已分配内存的指针。 现在,调试目的非常有趣,知道如何 这个指针指向的已分配内存块很大。
有没有什么比通过盲目地跑过边界而引发异常更优雅?
提前致谢, 安德烈亚斯
我在Windows上使用VC ++ 2005,在Linux上使用GCC 4.3
我在VC ++ 2005下有_msize
不幸的是,它会在调试模式中导致异常....
好。我尝试过上面描述的方式,但有效。 至少在我调试时并确保在通话结束后立即进行 到库出口我跑过缓冲区边界。像魅力一样。
它不优雅,在生产代码中无法使用。
答案 0 :(得分:23)
这不是标准的,但如果你的图书馆有一个msize()
函数可以给你大小。
一个常见的解决方案是使用您自己的函数来包装malloc
,该函数记录每个请求以及大小和结果内存范围,在发布版本中您可以切换回“真实”malloc
。
答案 1 :(得分:12)
如果你为了调试而不介意低级暴力,你可以#define宏挂钩对malloc和free的调用,并用大小填充前4个字节。
调整
void *malloc_hook(size_t size) {
size += sizeof (size_t);
void *ptr = malloc(size);
*(size_t *) ptr = size;
return ((size_t *) ptr) + 1;
}
void free_hook (void *ptr) {
ptr = (void *) (((size_t *) ptr) - 1);
free(ptr);
}
size_t report_size(ptr) {
return * (((size_t *) ptr) - 1);
}
然后
#define malloc(x) malloc_hook(x)
等等
答案 2 :(得分:10)
C运行时库不提供此类功能。此外,故意激发异常也不会告诉你这个块有多大。
通常,在C中解决此问题的方法是维护一个单独的变量,该变量跟踪分配的块的大小。当然,这有时不方便,但通常没有其他方法可以了解。
您的C运行时库可能提供一些可以查询已分配块的堆调试函数(毕竟,free()
需要知道块有多大),但是这种类型的任何一种事情将是不可移植的。
答案 3 :(得分:5)
使用gcc
和GNU linker
,您可以轻松打包malloc
#include <stdlib.h>
#include <stdio.h>
void* __real_malloc(size_t sz);
void* __wrap_malloc(size_t sz)
{
void *ptr;
ptr = __real_malloc(sz);
fprintf(stderr, "malloc of size %d yields pointer %p\n", sz, ptr);
/* if you wish to save the pointer and the size to a data structure,
then remember to add wrap code for calloc, realloc and free */
return ptr;
}
int main()
{
char *x;
x = malloc(103);
return 0;
}
并使用
进行编译gcc a.c -o a -Wall -Werror -Wl,--wrap=malloc
(当然,如果你愿意的话,这也适用于用g ++编译的c ++代码,以及new运算符(通过它的错位名称)。)
实际上,静态/动态加载的库也将使用您的__wrap_malloc
。
答案 4 :(得分:4)
不,除非在您的实施文档中,否则在超越其边界时不能依赖异常。这是你真正不需要知道编写程序的东西的一部分。如果您真的想知道,请深入了解编译器的文档或源代码。
答案 5 :(得分:4)
没有标准的C函数来执行此操作。根据您的平台,可能有一个不可移植的方法 - 您使用的操作系统和C库是什么?
请注意,引发异常是不可靠的 - 在您拥有的块之后可能会立即进行其他分配,因此在超出当前块的限制之后很久就不会出现异常。
答案 6 :(得分:4)
像Valgrind's memcheck和Google's TCMalloc(堆检查器部分)这样的内存检查程序可以跟踪这类事情。
您可以使用TCMalloc转储显示已分配内容的堆配置文件,或者您可以检查以确保使用SameHeap()在程序执行的两个点上堆相同。
答案 7 :(得分:2)
部分解决方案:在Windows上,您可以使用 PageHeap 来捕获已分配块之外的内存访问。
PageHeap是Windows内核中的备用内存管理器(在NT版本中,但现在没有人应该使用任何其他版本)。它会在进程中进行每次分配并返回一个内存块,该内存块的末尾与内存页面的末尾对齐,然后它使后续页面无法访问(无读取,无写入访问)。如果程序试图读取或写入块的末尾,您将获得一个访问冲突,您可以使用您喜欢的调试器。
如何获取:从Microsoft下载并安装适用于Windows的调试工具包:http://www.microsoft.com/whdc/devtools/debugging/default.mspx
然后启动GFlags实用程序,转到第3个选项卡并输入可执行文件的名称,然后按下该键。检查PageHeap复选框,单击OK,你就可以了。
最后一件事:当你完成调试时,不要忘记再次启动GFlags,并为应用程序禁用PageHeap。 GFlags将此设置输入注册表(在HKLM \ Software \ Microsoft \ Windows NT \ CurrentVersion \ Image File Execution Options \下),因此即使在重新启动时也是如此。
另外,请注意使用PageHeap可以极大地增加应用程序的内存需求。
答案 8 :(得分:1)
执行所需操作的方法是 BE 分配器。如果您筛选所有请求,然后将其记录以进行调试,那么您可以在内存空闲时找到所需内容。
此外,您可以在程序结束时检查是否已释放所有已分配的块,如果没有,则列出它们。这种雄心勃勃的图书馆甚至可以通过宏获取 FUNCTION 和 LINE 参数,让您准确了解泄漏内存的位置。
最后,Microsoft的MSVCRT提供了一个可调试的堆,它有许多有用的工具,您可以在调试版中使用它们来查找内存问题:http://msdn.microsoft.com/en-us/library/bebs9zyz.aspx
在Linux上,您可以使用valgrind查找许多错误。 http://valgrind.org/