calloc - Полезность обнуления памяти - PullRequest
10 голосов
/ 13 февраля 2010

В чем преимущество обнуления памяти (т.е. calloc() над malloc())? Не хотите ли вы изменить значение на что-то еще?

Ответы [ 7 ]

16 голосов
/ 13 февраля 2010

Существует два лагеря: один говорит, что инициализация переменных при их объявлении помогает находить ошибки. Люди в этом лагере удостоверяются, что все, что они объявляют, инициализировано. Они инициализируют указатели на NULL, int с на 0 и т. Д. Идея состоит в том, что все определено, и когда они видят NULL -показатель в отладчике, они сразу же узнают, что он был установлен неправильно. Это также может помочь при сбое программы во время тестирования из-за разыменования NULL -поинтера, а не из-за таинственного сбоя в производственном цикле.

Другой лагерь говорит, что инициализация переменных при объявлении усложняет отладку, потому что теперь компилятор не может предупреждать вас о переменных, «используемых без установки».

Не говоря вам о моих личных предпочтениях 1 : если вы принадлежите к первому лагерю, вы бы хотели calloc() вместо malloc(). Если вы принадлежите ко второму лагерю (который, очевидно, вы делаете), тогда вы предпочитаете malloc(), а не calloc().

Теперь есть два исключения:

  • Если вы принадлежите лагерю «инициализировать все», вы не calloc(), а malloc(), потому что вы инициализируете числа или указатели с плавающей запятой, и вы знаете, что все нулевые биты не обязательно означают 0 для них. Или вам не нужны дополнительные накладные расходы.
  • Если вы принадлежите к лагерю «установить, когда вам нужно», вы можете захотеть calloc(), когда вы выделяете некоторые данные и хотите, чтобы они были равны нулю. Например, если вы хотите вычислить построчную сумму n на m динамически распределенных int данных.

1 Вы можете посмотреть мои ответы на многие вопросы здесь на SO, чтобы увидеть, к какому лагерю я принадлежу: -).

8 голосов
/ 13 февраля 2010
  1. Зная, какое значение уже есть, программист может использовать некоторые ярлыки и выполнять определенные оптимизации. Чаще всего calloc структура с указателями: они инициализируются в NULL.
  2. Что если программист забыл что-то инициализировать в распределении? Вместо случайных вещей ноль - отличное значение по умолчанию.

В системе управления процессами в реальном времени, над которой я работал давно, мы решили, что логика включения инициализирует всю оперативную память до 0xCC, инструкции interrupt 3 8086. Это приведет к тому, что процессор войдет в монитор (примитивный отладчик), если он каким-то образом выполнит неинициализированную память. (Бесполезно, 8086 весело выполняет память, содержащую нули, поскольку они являются add [bx+si],al инструкциями. Даже 32-битный режим заставляет их быть add [ax],al инструкциями.)

Я не помню, нашли ли мы когда-либо беглую программу, но значения, соответствующие 0xCC, в различных значениях: 52 428 (16-разрядный без знака), -19 660 (16-разрядный со знаком), -107374176 (32-разрядный с плавающей запятой), и -9.25596313493e + 61 (64-разрядное число с плавающей запятой) появилось во многих неожиданных местах. Кроме того, некоторый код, ожидающий, что символы будут 7-битными ASCII, то есть ошибка, предупредил нас о его присутствии, когда он попытался обработать 0xCC.

3 голосов
/ 13 февраля 2010

Предположим, что вы хотите написать реализацию сортировки с подсчетом или сначала углубиться в поиск в графе и отслеживать посещенные вершины. По мере выполнения алгоритма вы обновите свою память (вместо того, чтобы назначать значение только один раз). Вам нужно инициализировать его до нуля в начале. Если у вас не было calloc, вам пришлось бы вручную пройти его и инициализировать его нулем в начале вашего алгоритма. calloc потенциально может сделать это более эффективно для вас.

1 голос
/ 13 февраля 2010

Хорошо знать, что все, что вы выделяете, инициализируется нулем. Многие ошибки возникли из кода, который использует неинициализированную память. Кроме того, некоторые значения по умолчанию в структурах / классах могут подойти как ноль, поэтому вам не нужно менять все значения после malloc.

Например, выделите структуру, в которой есть несколько указателей, с помощью malloc. Проверки NULL не всегда будут работать, если они не установлены в NULL. Если вы используете calloc, вам не нужно выполнять дополнительные шаги инициализации для значений указателя.

0 голосов
/ 19 февраля 2011

Никто не коснулся аспекта исполнения, поэтому, наверное, мне придется. Если вам нужно написать очень быструю программу, то malloc со встроенным memset «на всякий случай» - не лучший способ. Не имеет значения, насколько быстро работает memset, он всегда будет слишком медленным. Иногда вы должны инициализировать вектор или массив, чтобы реальная проблема заключалась в контроле ваших тактов (я не теряю их). Однажды я услышал цитату «никогда не следует отказываться от производительности случайно», которая означает, что с точки зрения производительности вы всегда должны знать, почему вы решили реализовать код тем или иным образом (каковы плюсы и минусы и как их сравнивают) друг друга в конкретном случае).

Если у вас есть буфер, который будет заполнен строкой, было бы неплохо инициализировать его до того, как строка будет заполнена, но большинство согласится, что это полная потеря тактов. Если вы пишете новую функцию str *, вы, возможно, захотите - для целей отладки - заполнить буфер значением, которое обычно не должно появляться, но оно будет удалено во время распространения.

Как уже упоминали другие, компилятор предупредит, если происходит обращение к неинициализированной переменной, поэтому, как я понимаю, суть в том, что на самом деле нет оправдания для инициализации "на всякий случай".

0 голосов
/ 31 марта 2010

Прежде всего, вы не можете вызывать указатели, по крайней мере, если вы хотите следовать стандарту C.

Во-вторых, ошибки просто маскируются, когда вы забиваете член всеми нулями. Намного лучше иметь отладочную версию malloc, которая инициализирует память чем-то, что всегда будет зависать, например, 0xCDCDCDCD.

Тогда, когда вы видите, как Access Voilation вы сразу же знаете проблему. Также полезно иметь функцию без отладки, которая будет сбивать память с другим шаблоном, чтобы те, кто касается памяти после ее освобождения, получили неожиданный сюрприз.

Работая над встроенной системой, вызывая просто «быть уверенным», обычно не вариант. Вы обычно выделяете и заполняете за один раз, так что calloc только для мужчин, вы дважды касаетесь памяти.

0 голосов
/ 13 февраля 2010

В дополнение к преимуществам инициализации переменных calloc также помогает отслеживать ошибки.

Если вы случайно используете немного выделенной памяти без надлежащей инициализации, приложение всегда будет зависать одинаково. Например, с нарушением прав доступа из нулевого указателя. С malloc память имеет случайные значения, и это может привести к сбою программы случайным образом.

Случайные сбои очень трудно отследить, и calloc помогает их избежать.

...