C中有没有办法找出动态分配内存的大小?
例如,之后
char* p = malloc (100);
有没有办法找出与之相关的内存大小p
?
C中有没有办法找出动态分配内存的大小?
例如,之后
char* p = malloc (100);
有没有办法找出与之相关的内存大小p
?
没有标准的方法可以找到这些信息。但是,一些实现提供了类似msize
的功能。例如:
但请记住,malloc 将分配请求的最小大小,因此您应该检查您的实现的 msize 变体是否实际返回对象的大小或实际在堆上分配的内存。
comp.lang.c 常见问题列表 · 问题 7.27 -
Q. 那么我可以查询
malloc
包以找出分配的块有多大吗?A. 不幸的是,没有标准或可移植的方式。(一些编译器提供非标准扩展。)如果您需要知道,您必须自己跟踪它。(另见问题7.28。)
C 的心态是为程序员提供工具来帮助他完成工作,而不是提供改变其工作性质的抽象。如果发生这种情况以牺牲性能限制为代价,C 还会尝试避免使事情变得更容易/更安全。
您可能希望对内存区域执行的某些操作只需要该区域开始的位置。此类事情包括使用以 null 结尾的字符串、操作该区域的前n个字节(如果已知该区域至少有这么大)等等。
基本上,跟踪区域的长度是额外的工作,如果 C 自动完成,它有时会不必要地这样做。
许多库函数(例如fread()
)需要一个指向区域开始的指针,以及该区域的大小。如果您需要区域的大小,则必须跟踪它。
是的,malloc() 实现通常会跟踪区域的大小,但它们可能会间接执行此操作,或者将其四舍五入到某个值,或者根本不保留它。即使他们支持它,与自己跟踪它相比,以这种方式找到大小可能会很慢。
如果您需要一个知道每个区域有多大的数据结构,C 可以为您完成。只需使用一个结构来跟踪该区域的大小以及指向该区域的指针。
不,C 运行时库不提供这样的功能。
一些库可能会提供特定于平台或编译器的函数来获取此信息,但通常跟踪此信息的方法是在另一个整数变量中。
这是我见过的创建标记指针以存储地址大小的最佳方法。所有指针函数仍将按预期工作:
盗自: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 调用。所有其他指针操作都不需要重构。
每个告诉你不可能的人在技术上都是正确的(最好的正确)。
出于工程原因,依靠 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);
}
测试:
_msize
malloc_usable_size
malloc_size
malloc
和本机 libc malloc_size
)USE_DL_PREFIX
就像其他人已经说过的那样:不,没有。
另外,我总是会避免所有供应商特定的功能,因为当你发现你真的需要使用它们时,这通常表明你做错了。您应该单独存储大小,或者根本不必知道它。使用供应商函数是失去用 C 编写的主要好处之一,即可移植性的最快方法。
我希望这取决于实现。
如果您获得了标头数据结构,则可以将其转换回指针并获取大小。
如果使用 malloc 则无法获取大小。
另一方面,如果您使用 OS API 来动态分配内存,例如 Windows堆函数,则可以这样做。
好吧,现在我知道这不是在回答您的具体问题,但是在框外思考……在我看来,您可能不需要知道。好的,好的,不,我并不是说你的实现不好或不正统......我的意思是你可能(不看你的代码我只是在猜测)你可能只想知道你的数据是否适合在分配的内存中,如果是这种情况,那么这个解决方案可能会更好。它不应该提供太多的开销,并且如果这确实是您正在处理的问题,它将解决您的“拟合”问题:
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);
并完成它。
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
注意: using_msize
仅适用于使用 , 等分配的内存calloc
。malloc
如 Microsoft 文档中所述
_msize 函数返回通过调用 、 或 分配的内存块的大小(以字节为
calloc
单位malloc
)realloc
。
否则会抛出异常。
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/msize?view=vs-2019
此代码可能适用于大多数 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);
}
我最近一直在努力可视化可写入的内存(即在 malloc 之后立即使用strcat
或strcpy
键入函数)。
这并不是一个非常技术性的答案,但它可以在调试时帮助你,就像它帮助我一样。
您可以使用您malloc
在 a 中的大小memset
,为第二个参数设置任意值(以便您可以识别它)并使用您从中获得的指针malloc
。
像这样:
char* my_string = (char*) malloc(custom_size * sizeof(char));
if(my_string) { memset(my_string, 1, custom_size); }
这可能有效,您的代码中的一个小更新:
void* inc = (void*) (++p)
size=p-inc;
但这将导致 1,即与p
if it is相关联的内存char*
。如果是,int*
那么结果将是 4。
没有办法找出总分配。