繁体   English   中英

这是要缓冲的正确大小吗?

[英]Is this correct size to buffer?

这是在64位计算机上容纳整数值和Unicode字符串的正确大小吗? 还是我错过了什么?

    DWORD errorMessageID = GetLastError();
        const wchar_t msgFmt[] = L"foo baaa. Error code = %d";
        wchar_t bufferMsg[sizeof(msgFmt) +        // room for fmt message string itself
            21 +  // enough to hold numbers up to 64-bits
            sizeof(wchar_t)         // byte-terminattor
        ];
        int nBytesWritten = swprintf_s(bufferMsg,
            msgFmt,
            sizeof(msgFmt),
            errorMessageID);

        MessageBox(NULL, 
                    bufferMsg,
                    TEXT("Copy to clipboard failed"), 
                    MB_OK | MB_ICONERROR);

除了Kirill Kobelev的答案中提到的传递给swsprintf_s()的参数的问题外 ,至少还有一些不太正确的事情,即使并非所有这些都会导致缺陷:

  • 即使为64位目标构建时,Windows SDK中的DWORD也是32位。 保留21个字符以对其进行格式化是有点过大了,但不是错误。 但是,这表明可能会导致其他问题的误解。
  • DWORD是无符号类型,因此使用“%d”格式化它不是很正确
  • 如果要格式化64位带符号的int格式,则“%d”仍然是使用错误的格式规范,因为它表明该参数是32位int类型。 您可能想使用“%lld”或“%I64d”之类的格式来格式化64位int类型。

不,这是不正确的。 正确的代码应如下所示:

const wchar_t msgFmt[] = L"foo baaa. Error code = %d";
wchar_t bufferMsg[sizeof(msgFmt)/sizeof(wchar_t) + // room for fmt message string itself
    21 +      // enough to hold numbers up to 64-bits
    1         // symbol-terminator
];
int nBytesWritten = swprintf_s(bufferMsg,
    sizeof(bufferMsg)/sizeof(wchar_t),
    msgFmt,
    errorMessageID);

在这两种情况下,都使用字节大小而不是元素数量加上参数顺序是错误的。 您调用MessageBox()函数是正确的。

手动维护sprintf调用目标所需的缓冲区大小很难维护。 让系统为您执行计算更加容易和安全。 Visual Studio附带的CRT为此提供了_scprintf系列功能。

以下代码说明了其用法。 它实现了一个函数,该函数采用格式字符串和可变数量的参数,并返回作为格式化结果的字符串:

std::wstring FormatString( const wchar_t* a_Format, ... ) {
    std::wstring text;
    va_list argList;
    va_start( argList, a_Format );
    // Calculate required buffer size
    size_t size = _vscwprintf( a_Format, argList ) + 1;
    va_end( argList );
    if ( size > 0 ) {
        // Dynamically construct buffer with the correct size
        std::vector<wchar_t> buffer( size );
        va_start( argList, a_Format );
        int count = _vsnwprintf_s( buffer.data(), size, size - 1,
                                   a_Format, argList );
        va_end( argList );
        if ( count >= 0 ) {
            // Construct return value
            text = std::wstring( buffer.data(), count + 1 );
        }
    }
    return text;
}

此函数返回一个std::wstring对象。 就像实现中使用的std::vector一样,它会自动为您管理内存,不需要显式的清理代码。 要将其与需要LPCWSTR参数的Windows API调用一起使用,请调用其c_str()成员。

在原始代码中使用此功能可将其压缩为以下内容:

DWORD errorMessageID = GetLastError();
MessageBoxW(NULL,
            FormatString( L"foo baaa. Error code = %u", errorMessageID ).c_str(),
            L"Copy to clipboard failed",
            MB_OK | MB_ICONERROR);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM