C中是否有办法找出动态分配内存的大小?
例如,在
之后char* p = malloc (100);
有没有办法找出与p
相关的内存大小?
答案 0 :(得分:42)
找不到此信息没有标准方法。但是,某些实现提供了msize
之类的功能来执行此操作。例如:
请记住,malloc将分配所请求大小的最小值,因此您应该检查实现的msize变量是否实际返回对象的大小或堆上实际分配的内存。
答案 1 :(得分:41)
comp.lang.c FAQ list · Question 7.27 -
Q值。那么我可以查询malloc
包以找出分配的块有多大吗?
一个。不幸的是,没有标准或便携的方式。 (有些编译器提供非标准扩展。)如果你需要知道,你必须自己跟踪它。 (另见问题7.28。)
答案 2 :(得分:10)
C心态是为程序员提供工具来帮助他完成工作,而不是提供改变工作性质的抽象。如果以牺牲性能限制为代价,C还会尽量避免使事情变得更容易/更安全。
您可能想要对内存区域执行的某些操作仅需要区域开头的位置。这样的事情包括使用以null结尾的字符串,操作区域的第一个 n 字节(如果已知该区域至少这么大),等等。
基本上,跟踪区域的长度是额外的工作,如果C自动完成,它有时会不必要地进行。
许多库函数(例如fread()
)需要指向区域开头的指针,以及该区域的大小。如果你需要一个区域的大小,你必须跟踪它。
是的,malloc()实现通常会跟踪区域的大小,但是它们可以间接地执行此操作,或者将其四舍五入到某个值,或者根本不保留它。即使他们支持它,与自己跟踪它相比,以这种方式找到大小可能会很慢。
如果您需要一个知道每个区域有多大的数据结构,C可以为您做到这一点。只需使用一个结构来跟踪区域的大小以及指向该区域的指针。
答案 3 :(得分:7)
不,C运行时库不提供这样的功能。
某些库可能提供可以获取此信息的特定于平台或编译器的函数,但通常跟踪此信息的方法是另一个整数变量。
答案 4 :(得分:4)
这是我见过创建标记指针以存储地址大小的最佳方法。所有指针函数仍将按预期工作:
被盗: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和免费通话。所有 其他指针操作不需要重构。
答案 5 :(得分:3)
就像其他人已经说过的那样:不,没有。
此外,我总是会避免使用特定于供应商的所有功能,因为当您发现确实需要使用它们时,这通常表明您做错了。您应该单独存储大小,或者根本不需要知道它。使用供应商功能是失去使用C语言编写便携性的主要好处之一的最快方法。
答案 6 :(得分:2)
我希望这是依赖于实现的 如果你有标题数据结构,你可以将它强制转换为指针并获得大小。
答案 7 :(得分:1)
如果使用malloc,则无法获得尺寸。
另一方面,如果您使用OS API动态分配内存,例如Windows heap functions,那么就可以这样做。
答案 8 :(得分:1)
此代码可能适用于大多数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);
}
答案 9 :(得分:1)
这可能有用,代码中的一个小更新:
void* inc = (void*) (++p)
size=p-inc;
但这会导致1,即与p
相关联的内存char*
。如果是int*
,那么结果将是4。
无法找到总分配。
答案 10 :(得分:1)
嗯现在我知道这不是回答你的具体问题,不过在盒子外面思考......它发生在我身上你可能不需要知道。好吧,好吧,不,我不是说你有一个坏的或非正统的实现...我的意思是你可能(没有看你的代码,我只是猜测)你可能只想知道你的数据可以适应分配的内存,如果是这种情况,那么这个解决方案可能会更好。它不应该提供太多的开销,并将解决你的&#34;拟合&#34;问题,如果这确实是你正在处理的事情:
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);
并完成它。
答案 11 :(得分:0)
每个人都告诉你这是不可能的在技术上是正确的(最好的正确)。
出于工程原因,依靠malloc子系统准确地告诉您已分配块的大小是一个坏主意。为了说服自己,想象一下你正在编写一个带有几个不同内存分配器的大型应用程序 - 也许你在一个部分中使用原始libc malloc
,但是在C ++ operator new
中另一部分,然后是另一部分中的一些特定Windows API。所以你有各种各样的void*
飞来飞去。编写一个可以在这些void*
的任何上工作的函数是不可能的,除非你能以某种方式告诉指针的值它来自哪个堆。
因此,您可能希望使用指示指针来自何处的约定(以及需要返回的位置)来包装程序中的每个指针。例如,在C ++中,我们称之为std::unique_ptr<void>
(对于需要operator delete
'd)或std::unique_ptr<void, D>
的指针(对于需要通过其他机制返回的指针D
})。如果你愿意,你可以在C中做同样的事情。一旦你将指针包装在更大的更安全的对象 中,它只是struct SizedPtr { void *ptr; size_t size; }
的一小步,然后你再也不用担心分配的大小。
<强>然而强>
还有充分理由说明为什么您可能合法地想知道分配的实际基础大小。例如,您可能正在为您的应用编写一个分析工具,该工具将报告每个子系统使用的实际内存量,而不仅仅是程序员认为的内存量他正在使用。如果你的每个10字节分配秘密使用16个字节,那就太知道了! (当然还会有其他开销,你没有用这种方式测量。但是 工作还有其他工具。)或许你只是在研究{{的行为1}}在你的平台上。或者,您可能希望“整理”不断增长的分配容量,以避免将来过早重新分配。例如:
realloc
要获得直接从libc malloc 返回的非空指针后面的分配大小 - 而不是从自定义堆返回,而不是指向对象的中间 - 你可以使用以下特定于操作系统的API,为方便起见,我将其捆绑到“portable-ish”包装函数中。如果您发现此代码不起作用的常见系统,请发表评论,我会尝试修复它!
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;
}
经过测试:
_msize
malloc_usable_size
malloc_size
#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);
}
和本地libc的malloc
)malloc_size
答案 12 :(得分:0)
Quuxplusone写道:“编写一个可以在任何这些void *上工作的函数都是不可能的,除非您能以某种方式从指针的值中得知它来自哪个堆。 Determine size of dynamically allocated memory in 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
答案 13 :(得分:0)
最近,我在可视化可写入的内存方面苦苦挣扎(即在malloc之后立即使用strcat
或strcpy
类型的函数)。
这并不是一个非常技术性的答案,但是它可以在调试时为您提供帮助,就像对我有帮助一样。
您可以使用malloc
中memset
的大小,为第二个参数设置一个任意值(以便您可以识别它),并使用从{{1}获得的指针}。
像这样:
malloc
答案 14 :(得分:0)
注意:使用_msize
仅适用于分配有calloc
,malloc
等的内存。如Microsoft文档所述
_msize函数返回内存块的大小(以字节为单位) 通过调用
calloc
,malloc
或realloc
分配。
否则将引发异常。
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/msize?view=vs-2019