我可以从变量参数函数中提前返回吗?

时间:2010-12-01 11:59:23

标签: c++ visual-c++ variadic-functions

假设我有两个用于调试输出的C ++函数:

void Trace( const wchar_t* format, ... )
{
    va_list args;
    va_start( args, format );
    VarArgTrace( format, args );
    va_end( args );
}

void VarArgTrace( const wchar_t* format, va_list args )
{
    WCHAR buffer[1024];
    //use ::_vsnwprintf_s to format the string
    ::OutputDebugStringW( buffer );
}

以上使用的是Win32 OutputDebugStringW(),但这并不重要。现在我想优化格式化,这样当没有调试器附加格式化时(我测量 - 加速很重要):

void Trace( const wchar_t* format, ... )
{
    if( !IsDebuggerPresent() ) {
        return;
    }
    //proceed as previously
    va_list args;
    .....
 }

我会在IsDebuggerPresent()返回null后提前返回的事实会影响除格式化之外的所有内容吗?

我的意思是我不再致电va_startva_end - 这有关系吗?是否会跳过va_startva_end导致任何意外的行为更改?

5 个答案:

答案 0 :(得分:6)

不,没有义务在varargs函数中使用va_start。

如果您不使用va_start,则无法使用va_end;如果你使用va_start,你应该使用va_end,无论函数如何返回。

答案 1 :(得分:1)

所有这些宏(至少在Windows上)都是arg列表中书签的指针操作。早点回来会好的。这是特定于编译器的,但我无法想象为什么早期返回会在其他平台上出现问题。

来自x86 vadefs.h

#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap)      ( ap = (va_list)0 )

答案 2 :(得分:1)

提前退货的唯一要求是,如果您使用过(已执行)va_start(),则必须在返回前使用va_end()

如果你藐视这条规则,你就可以在大多数系统上使用它,但某些系统需要va_end(),所以不要冒险忽略它。省略它是未定义的行为。

除了这条规则外,由您决定如何处理您的回报。你建议的早期回归不是问题。

答案 3 :(得分:1)

这是非常安全的,因为在C语言中,从堆栈中“清除”传递参数的工作总是由调用函数完成,而不是被调用函数。

有些语言(Pascal想到的)可能会反过来这样做。这可能更有效,但只能起作用,因为没有可变数量的参数的概念。

答案 4 :(得分:0)

varargs中没有太多开销,通常只是几个指针操作。 为每个varargs调用设置堆栈可能会略微增加开销,因此不是

void Trace( const wchar_t* format, ... )
{
    if( !IsDebuggerPresent() ) {
        return;
    }
    //proceed as previously
    va_list args;
    .....
 }

你可能最好使用预处理器来防止在非调试版本中调用跟踪内容。

使用

乱丢你的代码
if( IsDebuggerPresent() ) Trace( stuff... );

似乎也非常沮丧。

VC2010获得了可变参数宏了吗? :)