Почему функция CreateProcess изменяет переданную на вход командную строку?
Одна из неприятных особенностей функции CreateProcess
состоит в том, что параметр lpCommandLine
должен быть указателем на изменяемые данные. Если вы передадите указатель на память, которая не может быть изменена (например, указатель на страницу, помеченную PAGE_READONLY
), то все может повалиться. Комментатор Ritchie удивляется, почему этот параметр такой странный .
Вкратце, кто-то еще в 1980е хотел избежать выделения памяти . (Другая интерпретация этого: кто-то хотел быть черезчур умным.)
CreateProcess
временно изменяет строку, переданную в lpCommandLine
в попытке разобраться, где кончается имя программы и начинаются параметры командной строки. Функция могла бы снять копию со строки и сделать временные изменения в копии, но! если вы изменяете входную строку непосредственно, то вы экономите дорогостоящую операцию выделения памяти. В старые времена люди старались избегать выделений памяти, так что микро-оптимизации такого рода - это те вещи, о которых люди как правило беспокоились. Конечно, в наши дни, это выглядит достаточно устаревшим.
На самом деле, могут быть и серьезные технические причины (помимо чисто соображений производительности) избегать выделений памяти из кучи. Когда программа валится, отладчик "по месту" запускается функцией CreateProcess
, и вы не хотите выделять память из кучи, если причиной краха программы было повреждение кучи. Иначе вы можете получить рекурсивный цикл крахов : пытаясь запустить отладчик, вы валитесь, что означает - вы пытаетесь запустить отладчик для отладки нового краха , что опять валится, и так далее. Первоначальные авторы функции CreateProcess
были осторожны в плане избегания выделений памяти из кучи, так что в случае, когда функция вызывается для запуска отладчика, она не споткнется о поврежденную кучу.
Я не уверен, что эти соображения валидны по сей день, но именно эти соображения повлияли на первоначальный дизайн и, таким образом, интерфейс.
Почему затронута только Юникод-версия? Так это потому, что ANSI версия функции просто конвертирует свои строки в Юникод и потом зовет Юникод-версию функции. Таким образом, ANSI-версия функции реализует обход ошибки как побочный эффект своей первоначальной задачи: строка, переданная в Юникод-версию функции - это временная строка!
Упражнение: Почему для ANSI-версии CreateProcess
нормально выделять временную строку из кучи, а для Юникодной функции - нет?