Это правильный размер в буфер?

0

Является ли этот правильный размер для хранения целочисленного значения на 64-разрядной машине плюс строка в Юникоде? или я что-то упускаю?

    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);
  • 1
    Почему все проблемы? auto bufferMsg = L"foo baaa. Error code = %d"s + std::to_wstring(errorMessageID); Конечно, вы можете позаботиться о любых новых функциях, которые вы не можете использовать, но та же идея.
  • 1
    Серьезно подумайте о прочтении о FormatMessage()
Показать ещё 7 комментариев
Теги:
winapi

3 ответа

1
Лучший ответ

Нет, это неправильно. Правильный код должен выглядеть так:

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().

  • 0
    Обратите внимание, что использование _countof может быть понятнее, чем sizeof()/sizeof() . О, и вы выделили 2 символа вместо 1 для терминатора. :-)
  • 0
    Хорошо, я обновил длину буфера.
Показать ещё 5 комментариев
2

В дополнение к проблемам с аргументами, переданными swsprintf_s() упомянутым в ответе Кирилла Кобелева, есть, по крайней мере, еще несколько вещей, которые не совсем правильны, даже если не все из них приведут к дефекту:

  • DWORD в SDK Windows 32-бит, даже при создании для 64-битной цели. Резервирование 21 символа для форматирования - это немного перебор, но не ошибка. Однако это указывает на недоразумение, которое может привести к другим проблемам.
  • DWORD - это неподписанный тип, поэтому использование "% d" для форматирования не совсем правильно
  • если вы собираетесь форматировать 64-битный подписанный int, "% d" все равно будет использовать неправильный формат, поскольку он указывает, что аргумент представляет собой 32-битный тип int. Вы хотите использовать что-то вроде "% lld" или "% I64d" для форматирования 64-битного типа int.
0

Вручную рассчитывать необходимый размер буфера для назначения вызова sprintf трудно. Легче и безопаснее, если система выполнит расчет для вас. CRT, поставляемый с Visual Studio, предоставляет для _scprintf семейство функций _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 используемому в реализации, он автоматически управляет памятью для вас, и явный код очистки не требуется. Чтобы использовать его с вызовами Windows API, для которых требуется аргумент LPCWSTR вызывается его 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);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню