75

C中有没有办法找出动态分配内存的大小?

例如,之后

char* p = malloc (100);

有没有办法找出与之相关的内存大小p

4

15 回答 15

64

没有标准的方法可以找到这些信息。但是,一些实现提供了类似msize的功能。例如:

但请记住,malloc 将分配请求的最小大小,因此您应该检查您的实现的 msize 变体是否实际返回对象的大小或实际在堆上分配的内存。

于 2009-08-15T11:37:04.630 回答
55

comp.lang.c 常见问题列表 · 问题 7.27 -

Q. 那么我可以查询malloc包以找出分配的块有多大吗?

A. 不幸的是,没有标准或可移植的方式。(一些编译器提供非标准扩展。)如果您需要知道,您必须自己跟踪它。(另见问题7.28。)

于 2009-08-15T11:37:56.717 回答
15

C 的心态是为程序员提供工具来帮助他完成工作,而不是提供改变其工作性质的抽象。如果发生这种情况以牺牲性能限制为代价,C 还会尝试避免使事情变得更容易/更安全。

您可能希望对内存区域执行的某些操作只需要该区域开始的位置。此类事情包括使用以 null 结尾的字符串、操作该区域的前n个字节(如果已知该区域至少有这么大)等等。

基本上,跟踪区域的长度是额外的工作,如果 C 自动完成,它有时会不必要地这样做。

许多库函数(例如fread())需要一个指向区域开始的指针,以及该区域的大小。如果您需要区域的大小,则必须跟踪它。

是的,malloc() 实现通常会跟踪区域的大小,但它们可能会间接执行此操作,或者将其四舍五入到某个值,或者根本不保留它。即使他们支持它,与自己跟踪它相比,以这种方式找到大小可能会很慢。

如果您需要一个知道每个区域有多大的数据结构,C 可以为您完成。只需使用一个结构来跟踪该区域的大小以及指向该区域的指针。

于 2009-08-15T12:46:02.463 回答
10

不,C 运行时库不提供这样的功能。

一些库可能会提供特定于平台或编译器的函数来获取此信息,但通常跟踪此信息的方法是在另一个整数变量中。

于 2009-08-15T11:25:52.093 回答
10

这是我见过的创建标记指针以存储地址大小的最佳方法。所有指针函数仍将按预期工作:

盗自:https ://stackoverflow.com/a/35326444/638848

您还可以为 malloc 实现一个包装器,并在 malloc 返回的指针之前自由添加标签(如分配的大小和其他元信息)。这实际上是 c++ 编译器使用对虚拟类的引用来标记对象的方法。这是一个工作示例:

#include <stdlib.h>
#include <stdio.h>

void * my_malloc(size_t s) 
{
  size_t * ret = malloc(sizeof(size_t) + s);
  *ret = s;
  return &ret[1];
}

void my_free(void * ptr) 
{
  free( (size_t*)ptr - 1);
}

size_t allocated_size(void * ptr) 
{
  return ((size_t*)ptr)[-1];
}

int main(int argc, const char ** argv) {
  int * array = my_malloc(sizeof(int) * 3);
  printf("%u\n", allocated_size(array));
  my_free(array);
  return 0;
}

此方法相对于具有大小和指针的结构的优势

 struct pointer
 {
   size_t size;
   void *p;
 };

就是你只需要替换 malloc 和 free 调用。所有其他指针操作都不需要重构。

于 2016-04-20T05:02:12.297 回答
8

每个告诉你不可能的人在技术上都是正确的(最好的正确)。

出于工程原因,依靠 malloc 子系统准确地告诉您分配块的大小是一个坏主意。为了让自己相信这一点,想象一下你正在编写一个大型应用程序,有几个不同的内存分配器——也许你malloc在一个部分使用原始 libc,但在另一部分使用 C++ operator new,然后在另一部分使用一些特定的 Windows API。所以你有各种各样的void*飞行。编写一个可以处理任何这些void*不可能的函数,除非你能以某种方式从指针的值中分辨出它来自哪个堆。

因此,您可能希望使用一些约定来包装程序中的每个指针,这些约定指示指针来自哪里(以及需要返回到哪里)。例如,在 C++ 中,我们称之为std::unique_ptr<void>(对于需要operator delete'dstd::unique_ptr<void, D>的指针)或(对于需要通过其他机制返回的指针D)。如果你愿意,你可以在 C 中做同样的事情。无论如何,一旦您将指针包装在更大更安全的对象中,这只是一小步struct SizedPtr { void *ptr; size_t size; },然后您就不必再担心分配的大小了。

然而。

您可能有充分理由想知道分配的实际底层大小。例如,也许您正在为您的应用程序编写一个分析工具,该工具将报告每个子系统使用的实际内存量,而不仅仅是程序员认为他正在使用的内存量。如果您的每个 10 字节分配都在后台秘密使用 16 字节,那么很高兴知道!(当然也会有其他开销,您没有以这种方式测量。但是还有其他工具可以完成这项工作。)或者您可能只是在调查realloc您的平台上的行为。或者,也许您想“汇总”不断增长的分配容量以避免过早未来的重新分配。例子:

SizedPtr round_up(void *p) {
    size_t sz = portable_ish_malloced_size(p);
    void *q = realloc(p, sz);  // for sanitizer-cleanliness
    assert(q != NULL && portable_ish_malloced_size(q) == sz);
    return (SizedPtr){q, sz};
}
bool reserve(VectorOfChar *v, size_t newcap) {
    if (v->sizedptr.size >= newcap) return true;
    char *newdata = realloc(v->sizedptr.ptr, newcap);
    if (newdata == NULL) return false;
    v->sizedptr = round_up(newdata);
    return true;
}

要获取直接从 libc malloc 返回的非空指针(不是从自定义堆,也不是指向对象的中间)后面的分配大小,您可以使用以下特定于操作系统的 API,我为方便起见,已捆绑到“便携式”包装器功能中。如果您发现此代码不起作用的通用系统,请发表评论,我会尝试修复它!

#if defined(__linux__)
// https://linux.die.net/man/3/malloc_usable_size
#include <malloc.h>
size_t portable_ish_malloced_size(const void *p) {
    return malloc_usable_size((void*)p);
}
#elif defined(__APPLE__)
// https://www.unix.com/man-page/osx/3/malloc_size/
#include <malloc/malloc.h>
size_t portable_ish_malloced_size(const void *p) {
    return malloc_size(p);
}
#elif defined(_WIN32)
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/msize
#include <malloc.h>
size_t portable_ish_malloced_size(const void *p) {
    return _msize((void *)p);
}
#else
#error "oops, I don't know this system"
#endif

#include <stdio.h>
#include <stdlib.h>  // for malloc itself

int main() {
    void *p = malloc(42);
    size_t true_length = portable_ish_malloced_size(p);
    printf("%zu\n", true_length);
}

测试:

于 2018-02-04T20:11:34.203 回答
3

就像其他人已经说过的那样:不,没有。

另外,我总是会避免所有供应商特定的功能,因为当你发现你真的需要使用它们时,这通常表明你做错了。您应该单独存储大小,或者根本不必知道它。使用供应商函数是失去用 C 编写的主要好处之一,即可移植性的最快方法。

于 2009-08-15T12:32:51.383 回答
2

我希望这取决于实现。
如果您获得了标头数据结构,则可以将其转换回指针并获取大小。

于 2009-08-15T11:25:54.683 回答
1

如果使用 malloc 则无法获取大小。

另一方面,如果您使用 OS API 来动态分配内存,例如 Windows堆函数,则可以这样做。

于 2009-08-15T11:36:53.600 回答
1

好吧,现在我知道这不是在回答您的具体问题,但是在框外思考……在我看来,您可能不需要知道。好的,好的,不,我并不是说你的实现不好或不正统......我的意思是你可能(不看你的代码我只是在猜测)你可能只想知道你的数据是否适合在分配的内存中,如果是这种情况,那么这个解决方案可能会更好。它不应该提供太多的开销,并且如果这确实是您正在处理的问题,它将解决您的“拟合”问题:

if ( p != (tmp = realloc(p, required_size)) ) p = tmp;

或者如果您需要维护旧内容:

if ( p != (tmp = realloc(p, required_size)) ) memcpy(tmp, p = tmp, required_size);

当然你可以使用:

p = realloc(p, required_size);

并完成它。

于 2015-11-12T03:13:49.760 回答
1

Quuxplusone 写道:“编写一个可以处理任何这些 void*s 的函数是不可能的,除非你能以某种方式从指针的值中分辨出它来自哪个堆。” 确定 C 中动态分配内存的大小"

实际上,在 Windows 中,_msize 会根据指针的值为您提供分配的内存大小。如果该地址没有分配内存,则会引发错误。

int main()
{
    char* ptr1 = NULL, * ptr2 = NULL;
    size_t bsz;    
    ptr1 = (char*)malloc(10);
    ptr2 = ptr1;
    bsz = _msize(ptr2);
    ptr1++;
    //bsz = _msize(ptr1);   /* error */
    free(ptr2);

    return 0;
}

感谢#define 收藏。这是宏版本。

#define MALLOC(bsz) malloc(bsz)
#define FREE(ptr) do { free(ptr); ptr = NULL; } while(0)
#ifdef __linux__
#include <malloc.h>
#define MSIZE(ptr) malloc_usable_size((void*)ptr)
#elif defined __APPLE__
#include <malloc/malloc.h>
#define MSIZE(ptr) malloc_size(const void *ptr)
#elif defined _WIN32
#include <malloc.h>
#define MSIZE(ptr) _msize(ptr)
#else
#error "unknown system"
#endif
于 2019-02-16T17:10:47.010 回答
1

注意: using_msize仅适用于使用 , 等分配的内存callocmalloc如 Microsoft 文档中所述

_msize 函数返回通过调用 、 或 分配的内存块的大小(以字节为calloc单位mallocrealloc

否则会抛出异常。

https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/msize?view=vs-2019

于 2020-05-26T14:13:33.660 回答
0

此代码可能适用于大多数 Windows 安装:

template <class T>
int get_allocated_bytes(T* ptr)
{
 return *((int*)ptr-4);
}

template <class T>
int get_allocated_elements(T* ptr)
{
 return get_allocated_bytes(ptr)/sizeof(T);
}
于 2010-10-31T14:50:12.453 回答
0

我最近一直在努力可视化可写入的内存(即在 malloc 之后立即使用strcatstrcpy键入函数)。

这并不是一个非常技术性的答案,但它可以在调试时帮助你,就像它帮助我一样。

您可以使用您malloc在 a 中的大小memset,为第二个参数设置任意值(以便您可以识别它)并使用您从中获得的指针malloc

像这样:

char* my_string = (char*) malloc(custom_size * sizeof(char));
if(my_string) { memset(my_string, 1, custom_size); }

然后,您可以在调试器中可视化分配的内存的样子: 在此处输入图像描述

于 2019-10-31T12:54:03.013 回答
-1

这可能有效,您的代码中的一个小更新:

void* inc = (void*) (++p)
size=p-inc;

但这将导致 1,即与pif it is相关联的内存char*。如果是,int*那么结果将是 4。

没有办法找出总分配。

于 2011-07-29T08:02:18.947 回答