简体   繁体   English

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

[英]Is this correct size to buffer?

Is this the right size to hold a integer value on 64-bit machine plus a unicode string? 这是在64位计算机上容纳整数值和Unicode字符串的正确大小吗? or am I missing something? 还是我错过了什么?

    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);

In addition to the problems with the arguments passed to swsprintf_s() mentioned in Kirill Kobelev's answer , there are at least a few more things that aren't quite right, even if not all of them would result in a defect: 除了Kirill Kobelev的答案中提到的传递给swsprintf_s()的参数的问题外 ,至少还有一些不太正确的事情,即使并非所有这些都会导致缺陷:

  • a DWORD in the Windows SDK is 32-bits, even when building for a 64-bit target. 即使为64位目标构建时,Windows SDK中的DWORD也是32位。 Reserving 21 characters for formatting it is a small bit of overkill, but not a bug. 保留21个字符以对其进行格式化是有点过大了,但不是错误。 However, it's an indication of a misunderstanding that might result in other problems. 但是,这表明可能会导致其他问题的误解。
  • DWORD is an unsigned type, so using "%d" to format it isn't quite right DWORD是无符号类型,因此使用“%d”格式化它不是很正确
  • if you were going to format a 64-bit signed int, "%d" would still be the wrong format spec to use, since it indicates that the argument is a 32-bit int type. 如果要格式化64位带符号的int格式,则“%d”仍然是使用错误的格式规范,因为它表明该参数是32位int类型。 You would want to use something like "%lld" or "%I64d" to format a 64-bit int type. 您可能想使用“%lld”或“%I64d”之类的格式来格式化64位int类型。

No, this is not correct. 不,这是不正确的。 The right code should look like: 正确的代码应如下所示:

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);

In both cases you used the byte-size instead of the number of elements plus the order of params is wrong. 在这两种情况下,都使用字节大小而不是元素数量加上参数顺序是错误的。 You call of the MessageBox() function is correct. 您调用MessageBox()函数是正确的。

Manually calculating the required buffer size for the destination of an sprintf call is difficult to maintain. 手动维护sprintf调用目标所需的缓冲区大小很难维护。 It is easier and safer to have the system perform the calculation for you. 让系统为您执行计算更加容易和安全。 The CRT that ships with Visual Studio provides the _scprintf family of functions for this. Visual Studio附带的CRT为此提供了_scprintf系列功能。

The following code illustrates its usage. 以下代码说明了其用法。 It implements a function that takes a format string and a variable number of arguments and returns a string that is the result of formatting: 它实现了一个函数,该函数采用格式字符串和可变数量的参数,并返回作为格式化结果的字符串:

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;
}

This function returns a std::wstring object. 此函数返回一个std::wstring对象。 Just like the std::vector used in the implementation, it automatically manages memory for you, and no explicit cleanup code is required. 就像实现中使用的std::vector一样,它会自动为您管理内存,不需要显式的清理代码。 To use it with Windows API calls that require an LPCWSTR argument call its c_str() member. 要将其与需要LPCWSTR参数的Windows API调用一起使用,请调用其c_str()成员。

Using this function in your original code condenses it down to the following: 在原始代码中使用此功能可将其压缩为以下内容:

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