在Windows上使用va_copy是否安全

问题描述 投票:0回答:2

我已经使用va_list通过链接https://devblogs.microsoft.com/oldnewthing/20131114-00/?p=2663进行了潜在的陷阱

并且来自同一链接的以下代码段指定不要以所示方式使用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))

我的问题是,在Windows中将va_copy用于va_list是否安全?如果是,为什么,如果不是,那么前进的方向是什么?

c++ c c++11 variadic-functions variadic-macros
2个回答
1
投票

您不应该向内看香肠的制作方法。 :-)

好,现在您已经看了。并且您已经看到Windows并不是那些复杂的调用约定要求在va_list中分配内存的平台之一。事实证明,您实际上不需要使用va_copy而不是简单的赋值,并且va_end实际上不执行任何操作。不好你不应该看的现在您必须忘记所有这些。

因为明天一切都会改变。新的库或编译器优化逻辑的更新,或者谁知道什么,突然需要va_copyva_end防止内存泄漏,而您的有罪知识突然变成危险的错误。

标准说您必须使用va_copy复制va_list。标准说,您必须为每个初始化的va_end调用va_list。并且you必须这样做。因为您不知道没有业务往来的地方就无法知道平台上不需要它。

标准库不必遵守这些规则。它只需要在自己的环境中工作,就可以完全了解其平台及其内部的知识。如果有什么变化,维护标准库的优秀人员将意识到这一点,他们将确保新版本与平台上编译器的新版本兼容

所以就这样:实现将保证,如果您遵守规则,一切都会奏效。有了这些规则,以便实现者可以处理其平台的特殊性,从而使编译器可以挤出尽可能多的优化周期。

有时候,偷工减料和违反规则似乎无济于事,至少现在和现在都不会。但是不要屈服于这种诱惑。因为如果这样做,您已经在代码中留下了定时炸弹,该炸弹迟早会消失。


0
投票

如果您使用的编译器符合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);   
© www.soinside.com 2019 - 2024. All rights reserved.