In article <Xn***************************@194.125.133.14>,
Tomás Ó hÉilidhe <to*@lavabit.comwrote:
while ( *p++ = tolower( (char unsigned)*p ) );
[vs]
for ( ; *p = tolower((char unsigned)*p); ++p);
The former is "wrong" (invalid C code) and the latter is right,
because:
>I'm not entirely convinced however that there's a sequence point
violation in the following:
*p++ = tolower( (char unsigned)*p );
Any thoughts? There should be a sequence point at tolower's evaluation of
its arguments... right?
There is indeed a sequence point before a call. (I forget whether
C99 fixed the "loophole" in C89, where functions described in the
standard could be macros, and thus sidestep the sequence-point
requirements for function calls, but for the moment we may as well
assume tolower() really is a function-call.)
The problem is, the left-hand side (LHS) of the assignment operator
has no sequencing constraints with respect to the right-hand side
(RHS). So, although there is a sequence point before the call to
tolower(), the "for-its-address" ("lvalue") evaluation of *p++ on
the LHS could be not-at-all, partly, or completely evaluated at
the time the RHS evaluation begins. The use of *p on the right
then conflicts with the update of p in *p++ on the left. This
renders the behavior undefined.
If the behavior were not undefined already, then we might have to
start worrying about whether tolower() is a macro instead of a
function, and whether C99 has fixed the loophole. But the
corrected version is safe -- although I would probably write
it as:
while ((*p = tolower((unsigned char)*p)) != '\0')
p++;
myself (because I dislike empty loops, as they often need extra
checking to make sure they are not simply typographic errors in
the code).
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it
http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.