Почему этот MSVC API определяется таким образом? - PullRequest
1 голос
/ 29 мая 2011
errno_t _dupenv_s(
   char **buffer,
   size_t *sizeInBytes,
   const char *varname
);

У меня есть несколько вопросов по этому поводу:

  1. почему вместо указателя (*) требуется указатель на указатель (**)?
  2. почему sizeInBytes необходим, разве это не доступно strlen(buffer)?

Ответы [ 3 ]

4 голосов
/ 29 мая 2011

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

Защищенные функции все коды ошибок возврата, так что они могут быть проверены без возможности сбоя, и в связи с этим любые возвраты должны быть отправлены через указатели.И поскольку небезопасная версия strdup & dupenv возвращает char*, вы получаете двойное косвенное обращение, так что указатель на передаваемую вами переменную получает адрес выделенного буфера.

0 голосов
/ 29 мая 2011

В этом контексте тип char** является указателем на указатель на массив char s. (Это также может означать указатель на указатель на один char, но он не используется с _dupenv_s()).

Функция _dupenv_s() выделяет массив char с, запрашивая операционную систему зарезервировать некоторый кусок памяти, достаточно большой для его хранения. Операционная система резервирует часть памяти и дает функции _dupenv_s() адрес этого вновь выделенного массива char. Функция _dupenv_s() сохраняет адрес этого массива в переменной char*, так как это указатель на массив char s.

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

Если функция _dupenv_s() знает, где находится переменная char* вызывающего, то функция может пойти дальше и заполнить переменную char* вызывающего абонента правильным значением. Для этого вызывающему необходимо передать адрес переменной char* вызывающего. То есть вам нужно передать указатель на указатель на массив chars. Это означает, что char** должен быть пройден.

Обратите внимание, что это также причина, по которой sizeInBytes является size_t*. Вызывающая сторона имеет переменную size_t, и вызывающая сторона может передать адрес переменной в функцию как size_t*, чтобы функция могла заполнить переменную правильным значением.

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


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

0 голосов
/ 29 мая 2011

Нет, он запрашивает адрес символьного указателя. Метод выделит необходимое пространство для хранения значения переменной и установит на нее значение вашего указателя, в противном случае NULL. Обратитесь к примеру кода внизу страницы:

http://msdn.microsoft.com/en-us/library/ms175774(v=VS.80).aspx

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