【问题标题】:Variadic function fails in VC2010 and crashes in gcc可变参数函数在 VC2010 中失败并在 gcc 中崩溃
【发布时间】:2014-06-21 03:33:53
【问题描述】:

问题:

我的可变参数函数dbPRINT 有问题。它在 VS2010 中失败并在 GCC 4.8.1 上崩溃

正常的printf 打印我希望的exe 文件名,但我的dbPRINT 函数没有。我想这与我调用可变参数函数fprintf 的可变参数函数有关,还是与Unicode 有关?或者控制台根本不理解我给它的字符串?

代码:

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <irrlicht.h>
using namespace irr;

#define STR(x) #x
#define CAT(x) STR(x)
#define VAR(x) #x " = " CAT(x)

void dbPRINT( const char* formatString, ... )
{
    va_list p;
    va_start(p,formatString);
    fprintf( stdout, formatString, p );
    //fflush( stdout );
    va_end(p);
}

//! Return the full filename of the application executeable.
core::stringc GetExeFilename()
{
//! Windows
#if defined(_IRR_WINDOWS_API_)
    core::stringw tmp;
    wchar_t buf[ MAX_PATH ];
    buf[0] = L'\0';
    if (!GetModuleFileNameW( NULL, (LPWSTR)&buf, MAX_PATH))
    {
        return core::stringc("");
    }
    tmp = buf;  
    tmp.replace(L'\\', L'/');
    return core::stringc( tmp );
//! Posix
#elif defined (_IRR_POSIX_API_)
    c8 buf[1024];
    memset(buf, 0, sizeof(buf));
    if (readlink("/proc/self/exe", buf, sizeof(buf)-1))
    {
        perror("readlink");
        return tmp;
    }
    core::stringc tmp = buf;
    return tmp;
#else
    #warning GetExeFilename() not implemented for this platform.
#endif
    return core::stringc("");
}

//int main()
//int wmain( int argc, wchar_t** argv )
int main( int argc, char** argv )
{
    // MessageBox( 0, L"Press OK", L"Hi", MB_SETFOREGROUND );
    printf( VAR(WINVER) "\n");
    printf( VAR(_MSC_VER) "\n");
    printf( VAR(WIN32) "\n");
    printf( VAR(WIN64) "\n");

    #if defined(_IRR_WINDOWS_)
        dbPRINT( "#defined _IRR_WINDOWS_\n" );
    #endif

    #if defined(_IRR_WINDOWS_API_)
        dbPRINT( "#defined _IRR_WINDOWS_API_\n" );
    #endif

    #if defined(_IRR_POSIX_API_)
        dbPRINT( "#defined _IRR_POSIX_API_\n" );
    #endif

    #if defined(_IRR_WCHAR_FILESYSTEM)
        dbPRINT( "#defined _IRR_WCHAR_FILESYSTEM\n" );
    #endif

    #if defined(__GNUC__)
        dbPRINT( "#defined __GNUC__\n" );
    #endif

    printf(  "A %s\n", GetExeFilename().c_str() );      // works
    dbPRINT( "B %s\n", GetExeFilename().c_str() );      // fail
    dbPRINT( "C %s, %s\n", "Hallo ", "ANSI" );          // fail
    dbPRINT( "D Hello Information\n" );                 // works
    dbPRINT( "E Hello Error\n" );                       // works
    dbPRINT( "F %ls, %ls\n", L"Hallo ", L"UNICODE" );   // fail
    dbPRINT( "G Hello Information\n" );                 // works
    dbPRINT( "H Hello Error\n" );                       // works

    system("PAUSE");
    return 0;
}

结果:

WINVER = 0x0601
_MSC_VER = 1600
WIN32 = 1
WIN64 = WIN64
#defined _IRR_WINDOWS_
#defined _IRR_WINDOWS_API_
A X:/test_variadic_prints.exe        --> OK
B ¦V4                                --> Fail
C ­¼A, ¿ ?                            --> Fail
D Hello Information
E Hello Error
F G Hello Information                --> Fail ( F is empty ? )
H Hello Error
Drücken Sie eine beliebige Taste . . .

【问题讨论】:

    标签: c++ function variadic


    【解决方案1】:
    void dbPRINT(const char* fmt, ...)
    {
        va_list va;
        va_start(va, fmt);
        vprintf(fmt, va);
        fflush(stdout);
        va_end(va);
    }
    

    如果您不坚持刷新输出(我相信无论如何都会在打印换行符时隐式发生)和 void 返回类型,您可以使用函数指针将 fprintf() 别名为 dbPRINT()。

    也就是说,有几点说明:

    • 停止使用 C 样式强制转换。
    • 请注意,使用 win32 WCHAR 字符串不适用于此操作。
    • system("pause") 显然也是不可移植的。
    • 使用 C++ IOStreams,您可以使用 rdbuf() 以便灵活地重定向它们并且您将获得类型安全。
    • 使用幻数(如 4096)不会神奇地使代码正确。
    • GetModuleFilenameW() 可以使用任意长度的路径,但您的代码不能。调用它两次,首先确定长度,然后检索数据。

    【讨论】:

      【解决方案2】:

      我想我现在明白了,这个解决方案似乎有效

      void dbPRINT( const char* formatString, ... )
      {
          va_list p;
          va_start(p,formatString);
          const unsigned long int bufferSize = 4096;
          char buffer[bufferSize];
      #if defined(_MSC_VER)
          vsnprintf(&(buffer[0]), bufferSize, formatString, p);
      #elif defined(__GNUC__)
          vsnprintf(&buffer[0], bufferSize, formatString, p);
      #else
      
      #endif
          va_end(p);
          fputs( buffer, stdout );
          fflush( stdout );
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-12
        相关资源
        最近更新 更多