如何为缓冲区声明适当的大小

时间:2013-05-23 22:47:35

标签: c++ c visual-c++ memory-management buffer-overflow

我在我正在使用的Visual C ++项目中使用TCHAR,其定义如下所示:

#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的值 - 实际需要的精确缓冲容量(如果没有定义unicode则更小,如果定义了unicode则更大)?另外我想保护自己免受缓冲区溢出的可能性,我应该使用什么样的保护?

更重要的是,我在这里宣称缓冲区为char。如果我将缓冲区声明为int,那么大小值是否会有任何差异(即与声明为char相比,小4倍)?

更新

我想出的部分基于Mats Petersson的回答是:

    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;

思维正确还是错过了什么?

2 个答案:

答案 0 :(得分: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 :(得分:0)

  1. 你可以使用:snprintf / swnprintf,它会返回你需要的字符/ wchars的数量。
  2. 这里char buff[size] = {0};你在缓冲区之外写作。更新:如果 size 是常量的话,我会接受它 - 它只是一个初始化的声明。
  3. 如果上一个参数为"%s (ID: %i)",则此"%s (ID: %d)"应更改为:int