可能重复:
  我怎样才能获得C中指针的数组大小?
  有吗以编程方式确定C ++数组大小的任何方法?如果没有,为什么?

我从C样式函数中获取指向一块已分配内存的指针。 现在,调试目的非常有趣,知道如何 这个指针指向的已分配内存块很大。

有没有什么比通过盲目地跑过边界而引发异常更优雅?

提前致谢, 安德烈亚斯

编辑:

我在Windows上使用VC ++ 2005,在Linux上使用GCC 4.3

EDIT2:

我在VC ++ 2005下有 _msize 不幸的是,它会在调试模式中导致异常....

EDIT3:

好。我尝试过上面描述的方式,但有效。 至少在我调试时并确保在通话结束后立即进行 到库出口我跑过缓冲区边界。像魅力一样。

它不优雅,在生产代码中无法使用。

有帮助吗?

解决方案

这不是标准的,但是如果你的库有一个 msize()函数可以给你大小。

一个常见的解决方案是使用您自己的函数包装 malloc ,该函数记录每个请求以及大小和结果内存范围,在发布版本中您可以切换回“真实”的malloc

其他提示

如果你为了调试而不介意低级暴力,你可以#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)

等等

C运行时库不提供此类功能。此外,故意激发异常也不会告诉你这个块有多大。

通常,在C中解决此问题的方法是维护一个单独的变量,该变量跟踪分配的块的大小。当然,这有时不方便,但通常没有其他方法可以了解。

您的C运行时库可能提供一些可以查询已分配块的堆调试函数(毕竟, free()需要知道块有多大),但是任何此类事物都是不可移植的。

使用 gcc GNU链接器,您可以轻松地包装 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

不,除非在您的实施文档中,否则在超越其边界时不能依赖异常。这是你真正不需要知道编写程序的东西的一部分。如果您真的想知道,请深入了解编译器的文档或源代码。

没有标准的C函数来执行此操作。根据您的平台,可能有一个不可移植的方法 - 您使用的操作系统和C库是什么?

请注意,引发异常是不可靠的 - 在您拥有的块之后可能会立即进行其他分配,因此在超出当前块的限制之后很久就不会出现异常。

内存检查程序,如 Valgrind的memcheck Google的TCMalloc (堆检查器部分)跟踪这类事情。

您可以使用TCMalloc转储显示已分配内容的堆配置文件,或者您可以使用 SameHeap()

部分解决方案:在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可以极大地增加应用程序的内存需求。

执行所需操作的方法是 BE 分配器。如果您筛选所有请求,然后将其记录以进行调试,那么您可以在内存空闲时找到所需内容。

此外,您可以在程序结束时检查是否已释放所有已分配的块,如果没有,则列出它们。这种雄心勃勃的图书馆甚至可以通过宏获取 FUNCTION LINE 参数,让您准确了解泄漏内存的位置。

最后,Microsoft的MSVCRT提供了一个可调试的堆,它有许多有用的工具,您可以在调试版中使用它们来查找内存问题: http://msdn.microsoft.com/en-us/library/bebs9zyz.aspx

在Linux上,您可以使用valgrind查找许多错误。 http://valgrind.org/

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top