Thursday, April 7, 2011

stracpy: a strncpy replacement

strncpy
Unlike what the name suggests, strncpy is not for use on all strings. It was historically used in old versions of UNIX for writing a string into a fixed-width field such as a directory entry.

Therefore, its use on strings is problematic because it does not always terminate the destination string. Also, it does the "useless" task of copying null chars to the destination string if the length of source string is less than the specified amount. This function should be used with care or not used at all.

strncat
This is a true string function as it appends n chars and then a null char.

The new C standard: C1x
C1x is the newest revision of the C standard. It introduces "_s" (secure) versions of the string functions: strcpy_s, strcat_s, etc. These new functions require a third argument which specifies the maximum length of the destination buffer in order to avoid buffer overflows. The functions also return a negative number on failure. This adds too much complication on string manipulation, which should be a simple task.

The introduction of these new functions address a problem which has already been solved: buffer overflows. The gcc compiler already provides compile-time flags to check for buffer overflows. -fstack-protector aborts the program if a stack buffer overflow happens. Electric Fence works for heap buffer overflows. Mudflap works for both stack and heap buffer overflows. Therefore, the new string functions are unnecessary and add confusion.

The new string functions attempt to ungracefully fix a problem that really only has one ultimate solution: a char-compatible "string" data type (similar to C++'s).

stracpy
This function attempts to provide an alternative function that works the way strncpy should have been in the first place. It starts copying the specified amount of chars at the beginning of the string and guarantees that it will be null terminated.

char *stracpy(char *destination, const char *source, size_t amount)
{
while(amount--)
{
if((*destination++ = *source++) == '\0')
{
break;
}
}

*destination = '\0';

return destination;
}