Как объявить соответствующий размер для буфера

я использую TCHAR в проекте Visual C ++, над которым я работаю, определение которого показано ниже:

#ifdef _UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif

Мне нужно положить некоторые данные в буфер buff:

char buff[size] = {0};  // how to declare the buffer size - what should be its value ?
sprintf(buff, "%s (ID: %i)", res->name(), res->id());

где:

name() возвращается TCHAR*

id() возвращается int

Как рассчитать стоимость size — Точная емкость буфера для реальных потребностей (меньше, если не определен юникод, больше, если определен юникод)? Кроме того, я хотел бы защитить себя от возможности переполнения буфера, какую защиту я должен использовать?

Более того, я объявил здесь буфер как char, Если я объявлю буфер как intБудет ли какая-то разница для значения размера (т.е. в 4 раза меньше по сравнению с объявленным как char)?

ОБНОВИТЬ

Что я придумаю частично, основываясь на ответе Матса Петерссона:

    size_t len;
const char *FORMAT;
#ifndef _UNICODE
len = strlen((char*)res->name());
FORMAT = "%s (ID: %i)";
#else
len = wcslen(res->name());
FORMAT = "%S (ID: %i)";
#endif

int size = 7 * sizeof(TCHAR) +                             /* place for characters inside format string */
len * sizeof(TCHAR) +                           /* place for "name" characters */
strlen(_itoa(id, ioatmp, 10)) * sizeof(TCHAR) + /* place for "id" digits */
1 * sizeof(TCHAR);                              /* zero byte(s) string terminator */

char *buff = new char[size];  /* buffer has to be declared dynamically on the heap,
* because its exact size is not known at compilation time */
sprintf(buff, FORMAT, name, id);
delete[] buff;

Это правильное мышление или я что-то упустил?

1

Решение

Чтобы начать со спины, buff всегда должен быть charпотому что это то, что хранится sprintf,

Во-вторых, если ваш res->name() возвращает строку с широким символом (Unicode), ваша строка формата должна использовать "%S"для регулярного ASCII вы должны использовать "%s",

Теперь, чтобы вычислить длину, необходимую для буфера, и избежать переполнения. Это не так сложно сделать что-то вроде

      const TCHAR *nm = res->name();
size_t len;
#ifndef UNICODE
len = strlen(nm);
#else
... see below.
#endif

а затем угадать длину числа (целое число не может занимать более 12 мест) вместе с точным количеством символов, полученных как константы в строке формата.

Это прекрасно работает для стандартного варианта ASCII.

Однако с широким вариантом символа становится интереснее, поскольку он может занимать несколько байтов в выходной строке (например, писать китайские символы, которые всегда требуют многобайтового кодирования). Одним из решений является:

 len = snprintf(0, NULL, "%S", nm);

который должен дать вам правильный номер [я думаю]. Это довольно громоздкий метод, но он будет работать. Я не уверен, что есть простой способ преобразовать широкую строку в «количество байтов, необходимое для хранения этой строки» другим способом.

Редактировать: я бы серьезно подумал, стоит ли поддерживать вариант не-UNICOD, а затем просто перевести все на использование swprintf(...) вместо. Вам по-прежнему нужна длина, но она должна быть просто результатом wcslen(res->name())вместо того, чтобы требовать некоторого сложного вычисления конверсии.

1

Другие решения

  1. ты можешь использовать: snprintf / swnprintf, он вернет вам необходимое количество символов / символов.
  2. Вот char buff[size] = {0}; Вы пишете вне буфера. ОБНОВЛЕНИЕ: я возьму это назад — это просто объявление с инициализацией, если размер постоянно.
  3. этот "%s (ID: %i)" должны быть изменены на это: "%s (ID: %d)" если последний параметр int,
0