Windows10下_msize与VLA相关问题:等效函数及程序挂起原因
先明确前提:你的代码目标是Windows 10运行,_msize是微软特定的堆内存大小查询函数,其他系统需要替换为对应函数(比如Linux的malloc_usable_size),这点你已经说明得很清楚了。
先看Part 1:malloc分配的内存
用_msize(array)/sizeof(int)来计算数组元素数量,逻辑上是可行的,但你提到的「可能得到更大值」确实存在——因为malloc会为了内存对齐或者堆管理的需要,分配比你请求更大的内存块。比如你请求4个int(16字节),malloc可能分配32字节(取决于堆的对齐策略),这时候_msize返回的就是实际分配的大小,算出来的元素数就会比n大。不过这种情况确实不是核心问题,只要你知晓这个特性即可。
重点解答Part 2:变长数组(VLA)的两个问题
1. VLA有没有_msize的等效函数?
没有。原因很简单:
_msize是专门针对堆内存(由malloc/calloc/realloc分配的内存)设计的,它通过读取堆内存块头部的元数据来获取大小。- 而VLA是在栈上分配的局部变量,栈内存的管理由编译器和系统栈帧结构控制,没有公开的标准函数或微软特定API可以直接通过VLA的指针获取它的大小。
如果需要在函数中获取VLA的元素数量,最可靠的方式是把长度n作为参数一起传给函数,比如修改myfoo为:
void myfoo(int *array, int n) { printf("Nb elt of an array obtained from its pointer %d\n", n); }
2. 为什么调用_msize时程序挂起?
这是典型的未定义行为:_msize要求传入的指针必须是堆分配内存的起始地址。当你把VLA的指针(栈内存地址)传给_msize时,函数内部会尝试按照堆内存的结构去解析这个地址的元数据——但栈地址根本不在堆的内存范围内,这会导致非法内存访问,程序可能崩溃、挂起,或者输出毫无意义的结果。
在Windows下,_msize内部可能会做一些指针合法性检查,或者尝试访问堆的管理结构,当遇到无效的栈指针时,就可能触发访问违规导致程序卡死。
额外建议
如果你需要动态调整数组大小且要能查询内存大小,优先用malloc这类堆分配方式,而不是VLA。另外要注意:VLA是C11标准中的可选特性,Windows的MSVC编译器对VLA的支持并不完整(比如不能在函数参数中使用VLA类型),如果你的代码要兼容MSVC,可能需要避免使用VLA。
你的完整代码如下:
#include <stdio.h> #include <stdlib.h> #include <malloc.h> void myfoo(int *array) { printf("Nb elt of an array obtained from its pointer %d\n",_msize(array)/sizeof(int)); } int main() { int n=1; printf("Part 1 : malloc\n"); while(n>0) { printf("n : ");scanf("%d",&n); if (n<0) break; int *array; array=malloc(n*sizeof(int)); for (int i=0;i<n;i++) {array[i]=i;} myfoo(array); free(array); } n=1; printf("Part 1I : Variable Length Array\n"); while(n>0) { printf("n : ");scanf("%d",&n); if (n<0) break; int array[n]; for (int i=0;i<n;i++) {array[i]=i;} myfoo(array); } }
内容的提问来源于stack exchange,提问作者Stef1611

