Alternatives to modifying loop var in the loop.

K

Keith Thompson

Aleksandar Kuktin said:
Excuse me, but.... how is this loop supposed to stop. Exactly?

I assume it was meant to be something more akin to

while (*d++ == *s++);

but that the other `=' got lost somewhere.

An assignment yields the value that was assigned. That value
is the condition tested by the "while".

It's a bit terse for my own taste, but it's well defined and a common C
idiom.
 
J

James Kuyper

1. Calling strcpy is a lot clearer and most likely more efficient if these are char*.

If you need the value of either s or d after the loop has executed,
which is not a particularly uncommon need, the loop is better than a
call to strcpy(), and some modern compilers can optimize it almost as
much as strcpy() itself.
2. It is quite obvious what the code does. ...

I've met quite a few C programmers who couldn't answer that question,
and most of the ones who could were unable to explain why it works.
... It is much less obvious what the programmer wanted it to do.

True: dropping an '=' is easier than accidentally typing strcmp() when
you meant strcpy() (but I have in fact seen that done).
4. It wouldn't pass a code review where I work because it doesn't even compile. Two warnings, and warnings = error in all projects.

I only get one warning, about the use of = in a context where == might
have been meant - what's the other warning?
I have some sympathy with the idea of treating warnings as if they were
errors, but a certain amount of judgement is needed, too. A compiler is
free to warn about anything it wants - for instance, the use of a
obscene word as an identifier (or even the failure to use obscene words
as identifiers).
5. Calling a co-worker "moron" is a serious problem.

Agreed - even if the co-worker is in fact a moron, there's better ways
to deal with that fact.
 
J

James Kuyper

For example, if d is a pointer to unsigned 8 bit char, s is a pointer to unsigned int, and *s equals 256. It assigns 256 but ends up storing 0. How much would people be willing to bet on whether the loop ends or not, without checking a copy of the C Standard? And how much would people be willing to bet that this is the behaviour that the programmer intended?

"An assignment expression has the value of the left operand after the
assignment" (6.5.16p1); since that value is 0, it will terminate. That
seems perfectly clear and obvious to me, but then I'm an expert in such
things - I can't objectively assess how obvious it might be to less
experienced programmers.
 
A

Aleksandar Kuktin

An assignment yields the value that was assigned. That value is the
condition tested by the "while".

It's a bit terse for my own taste, but it's well defined and a common C
idiom.

*OH* *MY* *GOD*!! WHAT THE ****! Jesus merciful Christ! Wow! Talk about
the suprise factor. *Completely* sailed over my head. Really cool. Were
it not as beautiful as it is, I would call it an eldritch abomination.

But you know what is the funniest thing in all this?

I am actually well informed of the "assigment return value" (to use a bit
LISPy terminology), and have, infact, used it without thinking twice
about it, like in this function call...

fill_32field((recursion ? (listento = get_nbnsaddr(scope)) :
(listento = 0, brdcst_addr)),
(unsigned char *)&(addr.sin_addr.s_addr));

....it's just that that `while' up there confused me. I have developed a
reflex to never use a naked assigment operator in tests, in order to
avoid the notorious "assignment when you meant test equality" bug, and
that reflex kicked in when I saw the code snippet.
 
K

Keith Thompson

James Kuyper said:
If you need the value of either s or d after the loop has executed,
which is not a particularly uncommon need, the loop is better than a
call to strcpy(), and some modern compilers can optimize it almost as
much as strcpy() itself.

Or you can use the non-standard strlcpy() if you happen to have it (and
your coding standards permit it). It returns the total length of the
string it tried to create, as a size_t; you can add that to the base
address to get a pointer to the end of the string.
 
G

glen herrmannsfeldt

(snip)
With the tendency of compiler writers to add more and more
warnings, justified or not, I don't believe in the requirement
to code without warnings.
I only get one warning, about the use of = in a context
where == might have been meant - what's the other warning?
I have some sympathy with the idea of treating warnings as
if they were errors, but a certain amount of judgement is needed,
too. A compiler is free to warn about anything it wants - for
instance, the use of a obscene word as an identifier
(or even the failure to use obscene words as identifiers).

There was a story many years ago about a school that had a
compiler that would refuse to compile programs with obscene words
in them, I believe even in comments. The students then figured out
how to write them vertically, such that the compiler didn't notice.

Also, another story about obscene words added in lower case, on
a system where the printer ignored lower case characters. He was
caught after a new printer was installed.

-- glen
 
J

Joe keane

That particular warning is not enabled by default so you can simply,
well, not enable it. I guess that's sort of like turning it off.

How about this:

const char foo[6] = "abcdef";
 
G

glen herrmannsfeldt

How about this:
const char foo[6] = "abcdef";

Perfectly legal to me, but I suppose some compilers will warn
about it. If you want the null terminator, you should:

const char foo[] = "abcdef";

instead. Or:

char *foo="abcdef";

(with or without const) which has a different meaning, but
sometimes is more useful.

-- glen
 
K

Keith Thompson

That particular warning is not enabled by default so you can simply,
well, not enable it. I guess that's sort of like turning it off.

How about this:

const char foo[6] = "abcdef";

What about it? What are you asking? (gcc 4.7.2 at least doesn't warn
about it with "-Wall -Wextra".)
 
G

glen herrmannsfeldt

(e-mail address removed) wrote:

(snip)
About "an assignment expression has the value of the left
operand after the assignment": The rule is clear,
but you could easily imagine a language "alternative-C"
where the rule is "an assignment expression has the value
of the right operand before the assignment". It's rare
that it makes a difference, but I think it is too subtle
that I would accept code that relies on that tiny difference.

PL/I multiple assignment is of the form:

A, B, C, D = 3;

Where I believe that the right hand side is assigned to all
the variables. Otherwise, = is both the relational operator
and also used for assignment statments (it is not an assignment
operator).

A=B=C;

will assign 1 or 0 (converted from '1'B or '0'B) to A,
depending on B equalling C, or not.

-- glen
 
G

glen herrmannsfeldt

(snip, I wrote)
That's correct for PL/I. It's usually described as being equivalent
to:
T=3;
A=T;
B=T;
C=T;

In the case of an expression more complicated than 3, I suppose so.
Algol is the same, although the syntax is different ("A := B:= C :=
D:= 3").
I believe that in languages supporting multiple assignment, the PL/I /
Algol behavior is much more common.
C/C++ is sort-of different, but it doesn't really have multiple
assignment at all, just that assignment has a slightly unusual side
effect which can be used to do something that *looks* like multiple
assignment. Still, someone coding "dbl = intgr = 3.7;" should
probably be assigning a good wrist slapping.

Well, someone coding

intgr=3.7;

probably should also get a wrist slapping.

In Java, it would be considered a narrowing conversion and
require a cast. That would also catch some of the others
mentioned in this thread.

-- glen
 
B

BartC

That's correct for PL/I. It's usually described as being equivalent
to:

T=3;
A=T;
B=T;
C=T;

Algol is the same, although the syntax is different ("A := B:= C :=
D:= 3").

I believe that in languages supporting multiple assignment, the PL/I /
Algol behavior is much more common.

C/C++ is sort-of different, but it doesn't really have multiple
assignment at all, just that assignment has a slightly unusual side
effect which can be used to do something that *looks* like multiple
assignment.

The above would be more like:

D=3;
C=D;
B=C;
A=B;

in C. And in all these cases, where A, B, C, D are different types, they can
all end up with different values anyway!

Also in: A=B=C=A, it would be quite possible for A to change (using
something
like your dbl:=intgr example).

I think only with dynamic typing, would A, B, C, D all be assigned exactly
the same value (in some languages, it's not even four separate copies of it,
they would all refer to the same actual data!).
 
B

Ben Bacarisse

Rosario193 said:
ok
what about: "for(;*d=*s; ++d, ++s);"?

It's different to the original, but my first reaction is why write this
as a for loop? There seems to be a tradition of "for abuse" in some
places:

while (*d = *s) ++d, ++s;

Equally, this could be called "comma abuse" so maybe, if you want the
alternate semantics, you might write it:

while (*d = *s) { ++d; ++s; }
 
A

Aleksandar Kuktin

That particular warning is not enabled by default so you can simply,
well, not enable it. I guess that's sort of like turning it off.

How about this:

const char foo[6] = "abcdef";

What about it? What are you asking? (gcc 4.7.2 at least doesn't warn
about it with "-Wall -Wextra".)

No NULL terminator. String six chars long is stored in a buffer six chars
long.
 
R

Rosario193

It's different to the original,

the only difference i see it is for "for", d and s point to a \0 byte
at end

and in the while loop d and s poiunt at end one char afther \0 one
but my first reaction is why write this
as a for loop?

if someone want to use only "for loop" and never "while() loop", can
simplify a little the language [one word less in the language]
 
J

James Kuyper

That particular warning is not enabled by default so you can simply,
well, not enable it. I guess that's sort of like turning it off.

How about this:

const char foo[6] = "abcdef";

What about it? What are you asking? (gcc 4.7.2 at least doesn't warn
about it with "-Wall -Wextra".)

No NULL terminator. String six chars long is stored in a buffer six chars
long.

True - which might or might not be a problem, depending upon whether or
not the author intended that to be the case. Keith was probably well
aware of that - the question is, what was Joe's point in bringing that up?
 
J

James Kuyper

The second warning is about

while (xxx);

Single semicolon after the while condition without intervening white space is quite possibly a mistake. This one is most likely intentional:

while (xxx)
;

Odd - I've used that construct occasionally, and I always wrote it the
first way, which seems more natural to me. My compiler doesn't warn
about that issue with the settings I use.
I'm currently using Clang for everything; there is a list of about 40 warnings that can be turned on/off, and there are maybe five that we have disabled because they warn about things that are indeed not justified. If I have to change

while (*d++=*s++);

to

while ((*d++ = *s++) != 0)

How do you decide when to stop adding !=0? All of the following mean the
same thing:

while (a)
while (a!=0)
while ((a!=0) !=0)
etc.

My policy is to stop adding !=0 before the first time.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,075
Messages
2,570,547
Members
47,197
Latest member
NDTShavonn

Latest Threads

Top