我已经使用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是否安全?如果是,为什么,如果不是,那么前进的方向是什么?

最佳答案

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

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

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

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

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

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

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

09-07 06:48