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实际需要的精确缓冲区容量的值(如果没有定义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;

这是正确的想法还是我错过了什么?

4

2 回答 2

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()),而不是需要一些复杂的转换计算。

于 2013-05-23T23:06:13.700 回答
0
  1. 您可以使用:snprintf / swnprintf,它将返回您需要的字符数/wchars。
  2. 在这里,char buff[size] = {0};您正在缓冲区之外写入。更新:我会收回它 - 如果大小是恒定的,它只是一个带有初始化的声明。
  3. "%s (ID: %i)"应更改为:"%s (ID: %d)"如果最后一个参数是int.
于 2013-05-23T23:00:53.560 回答