throopw@xyzzy.UUCP (Wayne A. Throop) (12/16/88)
In the code fragment posted in this line of conversation, there was one "style fault" that could actually qualify as a bug under draft X3J11, and which therefore I felt ought to be pointed out. Now when I got done with the posting, I found I had picked on four more points of style in the code fragment, and my posting had ended up looking like a hatchet job rather than a warning of a nonportable practice. Well, rather than pare down my nits to the most important one, I'm posting the whole critique. I hope folks won't take this as the hatchet job it superficially resembles, but will take in the way it was intended: an important warning followed by four stylistic afterthoughts that I really and truely think result in code of "superior style". Happy coding, and if you feel I've been too harsh despite the disclaimer, feel free to email me and vent your spleen. The fragment in question is: void strupr( s ) char s[]; { int p = 0; while ( s[p] != NULL ) { s[p] = toupper( s[p] ); p++; } } /* strupr */ My comments, in decreasing order of urgency (or increasing order of pickiness) are these. First, comparing a character to NULL is stylistically wrong in K&R C, since NULL is to be used in pointer contexts (just as FALSE or NO or whatnot is to be used in "boolean" contexts). In draft X3J11 C, this is even a potential error, since NULL can legitimately be defined as ((void *)0), in which case an implementation (I think) is allowed to diagnose an error in the above comparison. Second, the loop control is scattered over the body of a while, which is exactly what the for loop was invented for. Third, the function might as well return s instead of void, so that it can be slipped unobtrusively into expressions instead of forcing separate statements or awkward expressions. Fourth, it isn't indicated that ctype.h ought to be included. (This is, of course, fairly obvious, and may have been omitted on purpose...) Fifth, the object of this excersize is somewhat more naturally cast in terms of pointers rather than subscripting in C. Two marginal justifications for this are that first it is more natural to step along an array once by pointers, and second compilers with few or no optimizing smarts will generate better code for the pointer case on most (but not all) architectures. (This, of course, is a really picky, obnoxiously finicky nit.) Applying all of these, we get the "improved" fragment (using prototypes): #include <ctype.h> char *strupr( char *s ) { register char *p; for( p=s; *p != '\0'; p+=1 ) *p = toupper( *p ); return( s ); } Note that some might prefer the condition in the for loop to be *p != 0 or just *p (In fact, I prefer just *p myself, but most folk seem to prefer the explicit comparison to a character value.) -- "Leave him alone. He is already neutralized." "I don't want neutral. I want dead." --- exchange in "Die Hard" -- Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw
msb@sq.uucp (Mark Brader) (12/20/88)
Wayne A. Throop (throopw@xyzzy.UUCP) made, in <2404@xyzzy.UUCP>, some criticisms of a certain piece of code including these lines: > > int p = 0; > > while ( s[p] != NULL ) { The last of these was: > Fifth, the object of this exercise is somewhat more naturally cast in > terms of pointers rather than subscripting in C. Wayne went on to cite two admittedly minor justifications for this. And I'd like to add another: avoiding the use of "int" for the subscript! Remember that "int" is allowed to be as small as 16 bits. It is quite conceivable that s[] has more than 32767 elements in it, so p can overflow, followed by God-knows-what (or as the X3J11 people say, by "undefined behavior"). A similar problem can exist if we make p "unsigned"; in this case it would be an infinite loop. On the other hand, some compilers wouldn't allow the object's dimension to exceed an int's range, so declaring p as "long" could be wasteful. If we use pointers instead of subscripts to step through the array, no such problem can exist. A pointer that points to the beginning of an array is guaranteed to be incrementable to the end of the array (plus one more time, in Draft ANSI C); and there is only one size of pointer variable (in true C, anyway): the right size. Mark Brader "Those who do not understand UNIX SoftQuad Inc., Toronto are condemned to repeat it." utzoo!sq!msb, msb@sq.com -- Henry Spencer