C strcpy() - evil?

前端 未结 17 1310
梦毁少年i
梦毁少年i 2020-12-23 10:50

Some people seem to think that C\'s strcpy() function is bad or evil. While I admit that it\'s usually better to use strncpy() in order to avoid bu

相关标签:
17条回答
  • 2020-12-23 11:10

    strlen finds upto last null terminating place.

    But in reality buffers are not null terminated.

    that's why people use different functions.

    0 讨论(0)
  • 2020-12-23 11:16

    I'm following the rules in here. Let me quote from it

    strncpy was initially introduced into the C library to deal with fixed-length name fields in structures such as directory entries. Such fields are not used in the same way as strings: the trailing null is unnecessary for a maximum-length field, and setting trailing bytes for shorter names to null assures efficient field-wise comparisons. strncpy is not by origin a ``bounded strcpy,'' and the Committee has preferred to recognize existing practice rather than alter the function to better suit it to such use.

    For that reason, you will not get a trailing '\0' in a string if you hit the n not finding a '\0' from the source string so far. It's easy to misuse it (of course, if you know about that pitfall, you can avoid it). As the quote says, it wasn't designed as a bounded strcpy. And i would prefer not to use it if not necessary. In your case, clearly its use is not necessary and you proved it. Why then use it?

    And generally speaking, programming code is also about reducing redundancy. If you know you have a string containing 'n' characters, why tell the copying function to copy maximal n characters? You do redundant checking. It's little about performance, but much more about consistent code. Readers will ask themselves what strcpy could do that could cross the n characters and which makes it necessary to limit the copying, just to read in manuals that this cannot happen in that case. And there the confusion start happen among readers of the code.

    For the rational to use mem-, str- or strn-, i chose among them like in the above linked document:

    mem- when i want to copy raw bytes, like bytes of a structure.

    str- when copying a null terminated string - only when 100% no overflow could happen.

    strn- when copying a null terminated string up to some length, filling the remaining bytes with zero. Probably not what i want in most cases. It's easy to forget the fact with the trailing zero-fill, but it's by design as the above quote explains. So, i would just code my own small loop that copies characters, adding a trailing '\0':

    char * sstrcpy(char *dst, char const *src, size_t n) {
        char *ret = dst;
        while(n-- > 0) {
            if((*dst++ = *src++) == '\0')
                return ret;
        }
        *dst++ = '\0';
        return ret;
    }
    

    Just a few lines that do exactly what i want. If i wanted "raw speed" i can still look out for a portable and optimized implementation that does exactly this bounded strcpy job. As always, profile first and then mess with it.

    Later, C got functions for working with wide characters, called wcs- and wcsn- (for C99). I would use them likewise.

    0 讨论(0)
  • 2020-12-23 11:16

    Well, strcpy() is not as evil as strdup() - at least strcpy() is part of Standard C.

    0 讨论(0)
  • 2020-12-23 11:17

    The reason why people use strncpy not strcpy is because strings are not always null terminated and it's very easy to overflow the buffer (the space you have allocated for the string with strcpy) and overwrite some unrelated bit of memory.

    With strcpy this can happen, with strncpy this will never happen. That is why strcpy is considered unsafe. Evil might be a little strong.

    0 讨论(0)
  • 2020-12-23 11:18

    Frankly, if you are doing much string handling in C, you should not ask yourself whether you should use strcpy or strncpy or memcpy. You should find or write a string library that provides a higher level abstraction. For example, one that keeps track of the length of each string, allocates memory for you, and provides all the string operations you need.

    This will almost certainly guarantee you make very few of the kinds of mistakes usually associated with C string handling, such as buffer overflows, forgetting to terminate a string with a NUL byte, and so on.

    The library might have functions such as these:

    typedef struct MyString MyString;
    MyString *mystring_new(const char *c_str);
    MyString *mystring_new_from_buffer(const void *p, size_t len);
    void mystring_free(MyString *s);
    size_t mystring_len(MyString *s);
    int mystring_char_at(MyString *s, size_t offset);
    MyString *mystring_cat(MyString *s1, ...); /* NULL terminated list */
    MyString *mystring_copy_substring(MyString *s, size_t start, size_t max_chars);
    MyString *mystring_find(MyString *s, MyString *pattern);
    size_t mystring_find_char(MyString *s, int c);
    void mystring_copy_out(void *output, MyString *s, size_t max_chars);
    int mystring_write_to_fd(int fd, MyString *s);
    int mystring_write_to_file(FILE *f, MyString *s);
    

    I wrote one for the Kannel project, see the gwlib/octstr.h file. It made life much simpler for us. On the other hand, such a library is fairly simple to write, so you might write one for yourself, even if only as an exercise.

    0 讨论(0)
提交回复
热议问题