2013-05-23 2 views
1

Я использую 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)?

UPDATE

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

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; 

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

+0

'buff [размер * sizeof (TCHAR)/sizeof (char)]'? –

+0

@Luchian Grigore: Нет, размер - это то, о чем я на самом деле спрашиваю - хочу узнать, как рассчитывается значение размера, исходя из того, что я знаю, какие данные будут переданы в него (данные: '' % s (ID:% i) ", res-> name(), res-> id()'). – jwaliszko

ответ

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

Объявление. 2 (* здесь 'char buff [size] = {0};' вы пишете за пределами буфера. *) - как я могу писать за пределами буфера здесь, поскольку я еще не определил его размер - вот что я Я действительно спрашиваю. – jwaliszko

+0

Просто имейте в виду, что только такая версия snprintf MS имеет такое поведение, обычно snprintf возвращает количество написанных символов. http://linux.die.net/man/3/snprintf – kfsone

1

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

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

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

 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 veariant, а затем просто перевести все это на использование swprintf(...). Вам все еще нужна длина, но она должна быть результатом wcslen(res->name()), а не требовать сложного вычисления преобразования.

+0

Наряду с моим редактированием внизу я попытался прояснить ситуацию '% S' и'% s'. –

+0

Обратите внимание, что использование sprintf не переносится (но тогда и TCHARs, хех). Также вы должны использовать _tcsclen (...), чтобы правильно получить длину TCHAR в единицах типа, 'size_t byteLen = _tcsclen (res-> name()) * sizeof (TCHAR);' – kfsone

+0

@Mats Petersson: +1 Спасибо за ваше время. Можете ли вы проверить обновление на мой вопрос, где я сделал расчет? Правильно ли это выглядит? Что с местом для символов внутри строки формата, я должен рассчитать его как '7 * sizeof (TCHAR)'? – jwaliszko

Смежные вопросы