2014-12-10 3 views
2

Это мой код (это и должен бытьчистый C):Почему calloc всегда возвращает NULL, когда я передаю «большой» размер?

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

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

Я хочу 64 Кб обнуленных памяти, что я буду использовать в цикле где-нибудь еще в моем приложении.

Unfortunatly calloc всегда возвращается NULL. Когда я использую его с 64 (байтами), он работает.

Я не уверен, как выделить «большие» блоки памяти, как в моем примере?

Edit: После прочтения комментариев, вот некоторые пояснения:

  1. malloc и memset имеют такое же поведение с тем же buffSize.
  2. sizeof(size_t) == 2sizeof(unsigned long) == 4 так что это 16-бит.
  3. Целевая платформа MS-DOS 6.22.

Итак, под 16-разрядной системой, как вы можете создать char * из 64 КБ с нулевым заполнением?

+0

Это скорее всего, OS/buildtree конкретный ответ, так что ... ОС построить дерево? – IdeaHat

+5

Работает ли malloc и memset? – mch

+3

Сумасшедшая идея, 'calloc (buffSize, 1)'. Также попробуйте 'unsigned long buffSize = 65536L; '. Я понятия не имею, какие ограничения на вашей платформе. – Persixty

ответ

4

Вы сказали, что 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_MAX максимальное значение типа size_t. Это макрос, определенный в <stdint.h>, который был введен в стандарте C99. Ваша реализация, вероятно, не поддерживает <stdint.h>. Выражение ((size_t)-1) эквивалентно.)

Вам, вероятно, не повезло, если вы не используете другую реализацию (что может означать использование одного и того же компилятора с разными опциями).

Возможно, вы можете переконфигурировать свою программу, чтобы использовать, например, два 32768-байтовых объекта, а не один объект размером 65536 байтов (хотя это может и не поддерживаться).

Системы MS-DOS поддерживают (поддерживаются?) Несколько моделей памяти, некоторые из которых могут позволить вам делать то, что вы хотите. Я не знаю подробностей. Для получения дополнительной информации обратитесь к документации вашего компилятора.

+0

Я пробовал 'block = calloc (64, 1024);' но, кажется, максимум, который я могу сделать, это '60, 1024' ... Может быть, это компилятор или система, я не знаю. – AlexV

+0

@AlexV: Как я уже сказал, если 'size_t' - 16 бит, то маловероятно, что ваша реализация может поддерживать объект размером более 65535 байт (и предел может быть меньше этого). Я боюсь, что это, вероятно, лучший ответ, который вы собираетесь получить - если вы не сможете вызвать свой компилятор в режиме, который позволяет создавать более крупные объекты (ищите «модели памяти»). –

1

Для 16-битного реального режима вам может потребоваться указать «огромную» модель, которая использует большие указатели для поддержки массивов> 65536. Возможно, что компактная или большая модель может работать с использованием одного фиксированного значения сегмента и смещения переменной для обработки размера буфера 65536. Я не знаю, какой набор инструментов вы используете, но должен быть параметр командной строки для указания модель памяти, которую будет использовать программа. Для 16-битных компиляторов реального формата Microsoft параметр/AH для огромных,/AC для компактных и/AL для больших.

Wiki ссылка: Intel Memory Models

Смежные вопросы