简体   繁体   中英

How to declare appropriate size for the buffer

I'm using TCHAR in the Visual C++ poject I'm working on, which definition is shown below:

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

I need to put some data into buffer 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());

where:

name() returns TCHAR*

id() returns int

How to calculate the value of size - exact buffer capacity for actual needs (smaller if no unicode is defined, bigger if unicode is defined) ? In addition I'd like to protect myself from buffer overflow possibility, what kind of protection should I use ?

What's more, I've declared here the buffer as char . If I declare the buffer as int , would it be any difference for the size value (ie 4 times smaller if compared to declared as char) ?

UPDATE

What I come up with partially based on Mats Petersson answer is:

    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;

Is it correct thinking or did I miss something ?

To begin from the back, buff should always be char , because that's what is being stored by sprintf .

Second, if your res->name() is returning a wide-char (unicode) string, your format string should use "%S" , for regular ASCII you should use "%s" .

Now, to calculate the length required for the buffer, and avoid overflows. It's not that hard to do something like

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

and then guesstimate the length of the number (an integer can't take more than 12 places), along with the exact number of characters produced as constants in the format string.

This works fine for the standard ASCII variant.

However, it gets more fun with the wide char variant, as that can take up multiple bytes in the output string (eg writing Chinese characters that always require multibyte encoding). One solution is:

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

which should give you the correct number [I think]. It's a pretty cumbersome method, but it will work. I'm not sure there is an easy way to convert a wide-string to "number of bytes needed to store this string" in another way.

Edit: I would seriously consider if it's much point in supporting non-UNICOD veariant, and then just convert the whole thing to using swprintf(...) instead. You still need the length, but it should just be the result of of wcslen(res->name()) , rather than requiring some complex conversion calculation.

  1. you can use: snprintf / swnprintf, it will return you number of chars/wchars needed.
  2. here char buff[size] = {0}; you are writing outside of the buffer. UPDATE: I'll take that back - it just a declaration with initialization if size is constant.
  3. this "%s (ID: %i)" shall be changed to this: "%s (ID: %d)" if last parameter is int .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM