对于大于 4GiB 的数组,在 64 位系统上调用 calloc 失败
Call to calloc fails on 64 Bit system for arrays which are greater than 4GiB
注意:我刚开始学习 C,这可能有一个我不知道的完全简单的解决方案。既然如此,还请赐教。
我在调试 C 程序时遇到问题,这是我从同事那里收到的。本质上,如果 n
大于 46341:
,我设法将段错误跟踪到对 calloc()
的失败调用
float *v = (float*) calloc(n * (n - 1)/2, sizeof(float));
下面是一组触发问题的最少代码:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]){
int ngenes = 46341;
float *v = (float*) calloc(ngenes * (ngenes - 1)/2, sizeof(float));
if(v) printf("Allocation succeeded\n");
free(v);
ngenes++;
v = (float*) calloc(ngenes * (ngenes - 1)/2, sizeof(float));
if(v) printf("Allocation succeeded\n");
free(v);
return 0;
}
ideone 上的相同代码。
据我所知,这正好是 4GiB,这就是我怀疑的原因。我试过的系统都是64位的,所以分配应该不是问题。在 SO 上四处搜索提出 calloc()
可能无法找到连续的 space,因此我尝试了几次对 calloc()
的调用,还尝试调用 realloc()
.最后,我尝试通过调用 float *v = new float[n * (n - 1)/2]()
来实现分配 n C++,这会引发 bad_alloc
错误。
我一直在尝试的系统:
$ uname -a
Linux picea 3.13.0-35-generic #62-Ubuntu SMP Fri Aug 15 01:58:42 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
$ free
total used free shared buffers cached
Mem: 396222336 368621612 27600724 32320 281536 346677332
-/+ buffers/cache: 21662744 374559592
Swap: 125061116 64894524 60166592
我试过编译:
gcc -m64 ...
无济于事。 运行 printf("%lu\n",SIZE_MAX);
returns 18446744073709551615
老实说,我没有想法。
您很可能是在 LP64 架构上编译它,其中 int
是 32 位,但 long
和指针是 64 位。大小计算最终以整数精度完成,然后 提升为 64 位,因此产生不正确的大小(负数,或比预期短得多)。
解决方案是使用
size_t ngenes = 46341;
相反。 size_t
是您应该用于内存中对象的大小和长度的类型。
注意:我刚开始学习 C,这可能有一个我不知道的完全简单的解决方案。既然如此,还请赐教。
我在调试 C 程序时遇到问题,这是我从同事那里收到的。本质上,如果 n
大于 46341:
calloc()
的失败调用
float *v = (float*) calloc(n * (n - 1)/2, sizeof(float));
下面是一组触发问题的最少代码:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]){
int ngenes = 46341;
float *v = (float*) calloc(ngenes * (ngenes - 1)/2, sizeof(float));
if(v) printf("Allocation succeeded\n");
free(v);
ngenes++;
v = (float*) calloc(ngenes * (ngenes - 1)/2, sizeof(float));
if(v) printf("Allocation succeeded\n");
free(v);
return 0;
}
ideone 上的相同代码。
据我所知,这正好是 4GiB,这就是我怀疑的原因。我试过的系统都是64位的,所以分配应该不是问题。在 SO 上四处搜索提出 calloc()
可能无法找到连续的 space,因此我尝试了几次对 calloc()
的调用,还尝试调用 realloc()
.最后,我尝试通过调用 float *v = new float[n * (n - 1)/2]()
来实现分配 n C++,这会引发 bad_alloc
错误。
我一直在尝试的系统:
$ uname -a Linux picea 3.13.0-35-generic #62-Ubuntu SMP Fri Aug 15 01:58:42 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
$ free total used free shared buffers cached Mem: 396222336 368621612 27600724 32320 281536 346677332 -/+ buffers/cache: 21662744 374559592 Swap: 125061116 64894524 60166592
我试过编译:
gcc -m64 ...
无济于事。 运行 printf("%lu\n",SIZE_MAX);
returns 18446744073709551615
老实说,我没有想法。
您很可能是在 LP64 架构上编译它,其中 int
是 32 位,但 long
和指针是 64 位。大小计算最终以整数精度完成,然后 提升为 64 位,因此产生不正确的大小(负数,或比预期短得多)。
解决方案是使用
size_t ngenes = 46341;
相反。 size_t
是您应该用于内存中对象的大小和长度的类型。