Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.1a 7/7/83; site rlgvax.UUCP Path: utzoo!linus!decvax!harpo!seismo!rlgvax!jeff From: jeff@rlgvax.UUCP (Jeffrey Kegler) Newsgroups: net.lang.c Subject: strncpy() Message-ID: <1020@rlgvax.UUCP> Date: Fri, 19-Aug-83 13:10:54 EDT Article-I.D.: rlgvax.1020 Posted: Fri Aug 19 13:10:54 1983 Date-Received: Fri, 19-Aug-83 17:01:54 EDT Organization: CCI Office Systems Group, Reston, VA Lines: 74 As most of you know, the UNIX philosophy is to have everything have explicit terminators, instead of being terminated by counts. In strcpy() this has raised the complaint that a slight error in an argument to strcpy() can result is destruction of a considerable amount of data. This could happen when the string to be copied is not properly terminated, or is a bad pointer, or is just overlong. One can say that it is really up to the programmer to check for these things. Another part of the UNIX philosophy is, wherever something might be seen as either a protection or a restriction of the programmer, depending on point of view, to assume it is a restriction. For those of us who do desire to be protected from our own lapses, especially when these lapses may lead to a core with its stack destroyed, strncpy() exists. It takes a third argument which gives an explicit maximum length to the string. However, for some strange reason, it still does not guarantee its result will be null terminated if it is overlong. Instead it puts characters right up into the last permitted location. Always writing strncpy(string1, string2, n); string1[n] = '\0'; solves the problem, but whenever I see this in code, I wonder why UNIX's string copy of explicitly n characters does not always result in a string of n characters. Further, it always copies a string of the length specified, adding nulls once the source string has been terminated. I can think of situations where this is useful, but one has never occurred to me, and far more often I wind up copying a string whose maximum length is 5000 and whose average length is 10. So as a byproduct of this feature, I would get an average of 4990 extra trips through the loop. Finally, strncpy() is far less efficient than it could be. Its main loop maintains and updates both a string pointer and a count, and each character copied requires a comparison to n, which is not is a register. I would get more into its behavior, but I do not know if the code is public domain, unlike strcpy(), 4 versions of which are in K&R on pages 100-101. Below is the code for my rewrite of strncpy(), which never accesses anything except a register in its main loop (if your compiler supports this sort of thing), has a main loop one instruction shorter on the VAX (all claims are for code generated by the C optimizer), guarantees the copied string will be a legal string, even where the original was not, and does no copying beyond the end-of-string. The main efficiency improvement does not depend on my changes from the behavior of strncpy(), and scpy() could be rewritten to simulate strncpy() exactly. =========================== /* * Copy a string in a fail-safe manner. */ void scpy(s1,s2,n) register char *s1,*s2; { register char *eos = s1+n-1; while(*s1++ = *s2++) if (s1 >= eos) { *eos = '\0'; return; } } ============================== One could argue that the above is not as fail-safe as it should be, because if n is zero or negative, the byte before s1 is zeroed, and a check for such an n could be placed before the main loop.