безопасно ли использовать va_copy на windows - PullRequest
1 голос
/ 06 марта 2020

Я прошел по ссылке https://devblogs.microsoft.com/oldnewthing/20131114-00/?p=2663 для потенциальных ловушек, используя va_list

И ниже сегмент кода из той же ссылки указывает не использовать va_list способом, показанным, потому что va_list не является прямое копирование.

BOOL FormatWithFallbackLanguage(
    DWORD dwMessageId, PCTSTR pszBuffer, SIZE_T cchBuffer, va_list ap)
{
 va_list apOriginal = ap;
 // Format from the user's preferred language.
 DWORD cchResult = FormatMessage(
               FORMAT_MESSAGE_FROM_HMODULE,
               g_hinst, dwMessageId, g_preferredLangId,
               pszBuffer, cchBuffer, &ap);
 // If that didn't work, then use the fallback language.
 if (cchResult == 0) {
  cchResult = FormatMessage(
               FORMAT_MESSAGE_FROM_HMODULE,
               g_hinst, dwMessageId, g_fallbackLangId,
               pszBuffer, cchBuffer, &apOriginal);
 }
 return cchResult != 0;
}

Статья в ссылке, предлагающая использовать va_copy для вышеуказанного сценария кодирования. Однако на windows в заголовочном файле stdarg.h va_copy, похоже, ничего не делает

#define va_copy(destination, source) ((destination) = (source))

Мой вопрос заключается в том, безопасно ли использовать va_copy в windows для va_list? Если да, то почему, а если нет, то как двигаться дальше?

Ответы [ 2 ]

2 голосов
/ 06 марта 2020

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

Хорошо, теперь вы посмотрели. И вы видели, что Windows не является одной из тех платформ, чье сложное соглашение о вызовах требует выделения памяти в va_list. Оказывается, вам не нужно использовать va_copy вместо простого присваивания и что va_end фактически ничего не делает. Это было плохо. Ты не должен был смотреть. Теперь ты должен все это забыть.

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

Стандарт гласит, что вы должны использовать va_copy для копирования va_list. Стандарт гласит, что вы должны позвонить va_end за каждый инициализированный va_list. И ты должен сделать это. Потому что вы не можете знать, что это не нужно на вашей платформе, не следя за тем, где вы не собираетесь заниматься бизнесом.

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

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

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

0 голосов
/ 06 марта 2020

Если используемый вами компилятор совместим с ISO C ++, тогда va_copy безопасен (это тавтология).

Возможно, что функция FormatMessage удаляет список, но я предполагаю, что это не так. Если это так, то другое предложение в связанной статье о перезапуске списка тоже не сработает.

Вы опробовали предложенный код? Правильное использование va_copy будет:

va_list ap2;
va_copy(ap2, ap);

DWORD cchResult = FormatMessage(
           FORMAT_MESSAGE_FROM_HMODULE,
           g_hinst, dwMessageId, g_preferredLangId,
           pszBuffer, cchBuffer, &ap);

if (cchResult == 0) 
    cchResult = FormatMessage(
           FORMAT_MESSAGE_FROM_HMODULE,
           g_hinst, dwMessageId, g_fallbackLangId,
           pszBuffer, cchBuffer, &ap2);

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