Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #93, СЕНТЯБРЬ 2006 г.

Трюки от Криса

 

Хакер, номер #093, стр. 093-146-3


Инициализировать или нет

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

Статические и глобальные переменные всегда инициализируются нулями еще на стадии загрузки PE/ELF файла в память, причем эта инициализация обходится очень дешево (в смысле процессорного времени), поэтому массивы (особенно больше) лучше всего размещать в статических переменных. Правда, при этом функция становится нереентерабельной, то есть ее нельзя вызывать рекурсивно или одновременно из нескольких потоков (ох, опять эти потоки!). Кроме того, при повторном вызове функции статические переменные будут содержать значения, оставленные предыдущим вызовом и, если функцию планируется вызывать многократно, то инициализировать переменные все-таки придется.

Память, выделенная функцией VirtualAlloc так же автоматически инициализируется нулями, о чем сказано в первом же абзаце документации ("Memory allocated by this function is automatically initialized to zero, unless the MEM_RESET flag is set"), да только кто же ту документацию читает…

Функция malloc не инициализирует выделяемую память (во всяком случае по Стандарту), но в реализации от Microsoft при выделении блоков от 512 Кб и выше она обращается к VirtualAlloc, в результате чего происходит неявная инициализация памяти. Правда, никаких гарантий, что поведение функции не изменится в следующих версиях у нас нет, так что пусть каждый решает сам — использовать ли ему эту недокументированную особенность или же свято придерживаться его величества Стандарта, в котором помимо malloc предусмотрена функция calloc, выделяющая инициализированную память. Надеюсь, никто не сморит, что "p = calloc(BLOCK_SIZE);" намного короче и нагляднее чем "p = malloc(BLOCK_SIZE); memset(p, 1, BLOCK_SIZE);", хотя по скорости выходит одно и то же, хотя Microsoft могла бы свободно избавиться от лишнего цикла инициализации, если блок памяти выделен VirtualAlloc, но — увы — она этого не сделала.

Наконец, существуют ситуации (правда, их довольно немного), когда начальное значение переменной совершенно некритично и потому ее можно не инициализировать, пропуская протест компилятора мимо ушей. Вот, например, реализация "пропеллера": "printf("%c\r","-\\|/"[z++ % 4]);" Совершенно очевидно, что инициализировать переменную z излишне, хоть это и влияет на начальное положение "лопасти", но… кто же на него обращает внимание?

Назад на стр. 093-146-2  Содержание