【问题标题】:Why does calloc always returns NULL when I pass a "big" size?当我传递“大”大小时,为什么 calloc 总是返回 NULL?
【发布时间】:2014-12-10 16:36:34
【问题描述】:

这是我的代码(它是并且必须纯C):

unsigned long buffSize = 65536; /* 64 KB */
char *block;

block = calloc(1, buffSize);
if (block == NULL)
{
    /* This is always triggered */
}

我想要一个 64 KB 的归零内存,我将在我的应用程序的其他地方循环使用它。

不幸的是calloc 总是返回NULL。当我将它与 64(字节)一起使用时,它可以工作。

我不确定如何像我的示例中那样分配“更大”的内存块?

编辑:看完cmets,这里有一些说明:

  1. mallocmemset 具有相同的行为与相同的 buffSize
  2. sizeof(size_t) == 2sizeof(unsigned long) == 4 所以它是 16 位的。
  3. 目标平台是 MS-DOS 6.22。

那么在 16 位系统下,如何创建一个 64 KB 零填充的 char *

【问题讨论】:

  • malloc 和 memset 工作吗?
  • 疯狂的想法,calloc(buffSize,1)。也可以试试`unsigned long buffSize = 65536L;'。我不知道你的平台有什么限制。
  • 64KB 并没有给我留下那么大的印象。我会问一个显而易见的问题,您的系统有多少可用内存?我可以建议您尝试将 buffSize 定义为 hving 类型size_t 甚至是普通的旧int。如果这不起作用,重复将增益大小减半并查看是否有有效的大小可能会很有趣。
  • unsigned long 必须至少为 32 位,但 size_t 可以想象为 16 位。您系统上的sizeof (size_t) 是什么? malloc(buffSize) 是否返回空指针?尝试6465536 之间的值范围;这是开始失败的特定尺寸吗?
  • 寻找farmalloc或类似功能。 (OMG farmalloc,多少个月亮过去了,没想到还能再见到你……)

标签: c malloc calloc


【解决方案1】:

你说过sizeof (size_t) == 2(这是针对MS-DOS 6.22)。

也就是说size_t的最大值是65535

unsigned long buffSize = 65536; /* 64 KB */

目前没有问题。 unsigned long 必须至少为 32 位(并且在您的系统上为 32 位),因此它可以轻松保存值 65536

char *block;

block = calloc(1, buffSize);

calloc 的两个参数都是 size_t 类型。任何不是size_t 类型的参数都会被隐式转换。将65536 转换为size_t 产生0。因此,您请求分配 0 个字节。这种分配的行为是实现定义的;它可以返回一个空指针,也可以返回一个唯一的非空指针,类似于malloc(1),只是你不一定可以取消引用它。您的实现显然是前者。

calloc 有两个参数,都是size_t 类型。它们的值不会简单地相乘以产生size_t 类型的结果。相反,calloc 必须要么成功分配指定的字节数要么失败并返回空指针。

原则上可以这样写:

block = calloc(64, 1024);

或类似的东西。如果成功,它将分配一个 65536 字节的对象。

但是由于size_t 只有 16 位,这几乎可以肯定意味着该实现不能创建大于最多 65535 字节的对象。没有实际禁止创建大于 SIZE_MAX 字节的对象,但任何能够这样做的实现几乎肯定会使它的 size_t 更大,以便它可以表示任何对象的大小。

(SIZE_MAXsize_t类型的最大值。它是在<stdint.h>中定义的宏,由C99标准引入。你的实现可能不支持<stdint.h>。表达式@987654347 @ 是等价的。)

您可能不走运,除非您使用不同的实现(这可能意味着使用具有不同选项的相同编译器)。

也许您可以重新设计您的程序,使其可以使用例如两个 32768 字节的对象而不是单个 65536 字节的对象(尽管这可能也不支持)。

MS-DOS 系统支持(支持?)多种内存模型,其中一些可能允许您做您想做的事。我不知道细节。有关详细信息,请参阅编译器的文档。

【讨论】:

  • 我试过block = calloc(64, 1024);,但似乎我能做的最大是60, 1024...可能是编译器或系统,我不知道。
  • @AlexV:正如我所说,如果size_t 是 16 位,那么您的实现不太可能支持大于 65535 字节的对象(并且限制可能小于该字节)。恐怕这可能是您将得到的最佳答案——除非您能够以允许更大对象的模式调用编译器(查找“内存模型”)。
【解决方案2】:

对于 16 位实模式,您可能需要指定“巨大”模型,它使用远指针来支持大小 > 65536 的数组。紧凑或大型模型可能会起作用,使用单个固定段值和可变偏移量来处理 65536 的缓冲区大小。我不知道您使用的是什么工具集,但应该有一个命令行参数来指定程序将使用的内存模型。对于 Microsoft 16 位实模式编译器,参数是 /AH 表示大,/AC 表示紧凑,/AL 表示大。

维基链接:Intel Memory Models

【讨论】:

    猜你喜欢
    • 2011-11-16
    • 1970-01-01
    • 2014-09-12
    • 2019-09-18
    • 2014-09-02
    • 2015-02-27
    • 2021-01-10
    • 1970-01-01
    • 2011-04-16
    相关资源
    最近更新 更多