2004-01-02 22:14:20

by Bill Davidsen

[permalink] [raw]
Subject: Re: GCC 3.4 Heads-up

Linus Torvalds wrote:

> Actually, those language extensions (while documented for a long time) are
> pretty ugly.
>
> Some of that ugliness turns into literal bugs when C++ is used.
>
> The cast/conditional expression as lvalue are _particularly_ ugly
> extensions, since there is absolutely zero point to them. They are very
> much against what C is all about, and writing something like this:
>
> a ? b : c = d;
>
> is something that only a high-level language person could have come up
> with. The _real_ way to do this in C is to just do
>
> *(a ? &b : &c) = d;
>
> which is portable C, does the same thing, and has no strange semantics.

I would probably write
( a ? b : c ) = d;
instead, having learned C when some compilers parsed ? wrong without
parens. Actually I can't imagine writing that at all, but at least with
parens humans can read it easily. Ugly code.

Your suggestion is not portable, if b or c are declared "register" there
are compilers which will not allow taking the address, and gcc will give
you a warning.


--
bill davidsen <[email protected]>
CTO TMR Associates, Inc
Doing interesting things with small computers since 1979


2004-01-03 22:34:34

by Krzysztof Halasa

[permalink] [raw]
Subject: Re: GCC 3.4 Heads-up

Bill Davidsen <[email protected]> writes:

> I would probably write
> ( a ? b : c ) = d;
> instead, having learned C when some compilers parsed ? wrong without
> parens. Actually I can't imagine writing that at all, but at least
> with parens humans can read it easily. Ugly code.
>
> Your suggestion is not portable, if b or c are declared "register"
> there are compilers which will not allow taking the address, and gcc
> will give you a warning.

One can write as well:

if (a)
b = d;
else
c = d;

Might be more readable and it is what the compiler does.
--
Krzysztof Halasa, B*FH

2004-01-04 05:47:55

by Bill Davidsen

[permalink] [raw]
Subject: Re: GCC 3.4 Heads-up

Krzysztof Halasa wrote:
> Bill Davidsen <[email protected]> writes:
>
>
>>I would probably write
>> ( a ? b : c ) = d;
>>instead, having learned C when some compilers parsed ? wrong without
>>parens. Actually I can't imagine writing that at all, but at least
>>with parens humans can read it easily. Ugly code.
>>
>>Your suggestion is not portable, if b or c are declared "register"
>>there are compilers which will not allow taking the address, and gcc
>>will give you a warning.
>
>
> One can write as well:
>
> if (a)
> b = d;
> else
> c = d;
>
> Might be more readable and it is what the compiler does.

Since that's a matter of taste I can't disagree. The point was that the
original post used
*(a ? &b : &c) = d;
which generates either warnings or errors if b or c is a register
variable, because you are not allowed to take the address of a register.
It seems gcc does it anyway by intuiting what you mean, but it's not
portable in the sense of being error-free code.

It was a nit, I didn't mean to start a controversy, although if "d" is
actually a complex expression it is certainly less typing as I showed
it, and prevents a future maintainer from changing one RHS and not the
other. That's defensive programming.


--
bill davidsen <[email protected]>
CTO TMR Associates, Inc
Doing interesting things with small computers since 1979

2004-01-04 20:41:23

by Linus Torvalds

[permalink] [raw]
Subject: Re: GCC 3.4 Heads-up



On Sun, 4 Jan 2004, Bill Davidsen wrote:
>
> Since that's a matter of taste I can't disagree. The point was that the
> original post used
> *(a ? &b : &c) = d;
> which generates either warnings or errors if b or c is a register
> variable, because you are not allowed to take the address of a register.

The thing is, the above case is the _only_ case where there is any point
to using a conditional expression and an assignment to the result in the
same expression.

If you have local variables (register or not), the sane thing to do is

if (a)
b = d;
else
c = d;

or variations on that. That's the readable code.

The only case where conditional assignment expressions are useful is when
you are literally trying to avoid doing branches, and the compiler isn't
smart enough to avoid them otherwise.

Check the compiler output some day. Try out what

int a, b;

void test_assignment_1(int val)
{
*(val ? &a : &b) = 1;
}

void test_assignment_2(int val)
{
if (val)
a = 1;
else
b = 1;
}

void test_assignment_3(int val)
{
(val ? a : b) = 1;
}

actually generate.

Hint: only the first one generates code without any jumps (on
architectures that have conditional moves and with "normal" compilers).

In short: the "*(a?&b:&c) = x" format actually has some advantages. It
also happens to be standard C. The "(a ? b : c) = x" format is not only
not real C code, but it has _zero_ advantages.

Linus

2004-01-05 01:28:23

by Bill Davidsen

[permalink] [raw]
Subject: Re: GCC 3.4 Heads-up

Linus Torvalds wrote:
>
> On Sun, 4 Jan 2004, Bill Davidsen wrote:
>
>>Since that's a matter of taste I can't disagree. The point was that the
>>original post used
>> *(a ? &b : &c) = d;
>>which generates either warnings or errors if b or c is a register
>>variable, because you are not allowed to take the address of a register.
>
>
> The thing is, the above case is the _only_ case where there is any point
> to using a conditional expression and an assignment to the result in the
> same expression.

We disagree, see below.

> If you have local variables (register or not), the sane thing to do is
>
> if (a)
> b = d;
> else
> c = d;
>
> or variations on that. That's the readable code.

But may lead to errors in maintenence. Your first example below avoids
that problem. Imagine instead of "d" you have a 40-50 character RHS. Now
imagine that the code needs to be changed. If you have the long
expression in two places then it invites the possiblility of someone
changing only one of them. You may never make mistakes, but the rest of
us do, and the conditional LHS avoids that.
>
> The only case where conditional assignment expressions are useful is when
> you are literally trying to avoid doing branches, and the compiler isn't
> smart enough to avoid them otherwise.
>
> Check the compiler output some day. Try out what
>
> int a, b;
>
> void test_assignment_1(int val)
> {
> *(val ? &a : &b) = 1;
> }

You pointed out that this generates good code, I pointed out that it
also avoids future errors and is not just a trick for broken compilers.
I take your point about generating good code, I'm sorry you can't see
that avoiding code duplication is good practice even without the benefit
of better code.

--
bill davidsen <[email protected]>
CTO TMR Associates, Inc
Doing interesting things with small computers since 1979

2004-01-05 02:25:56

by Linus Torvalds

[permalink] [raw]
Subject: Re: GCC 3.4 Heads-up



On Sun, 4 Jan 2004, Bill Davidsen wrote:
>
> You pointed out that this generates good code, I pointed out that it
> also avoids future errors and is not just a trick for broken compilers.
> I take your point about generating good code, I'm sorry you can't see
> that avoiding code duplication is good practice even without the benefit
> of better code.

Don't be silly. Using non-standard C is _never_ good practice.

If 'd' is a complex expression, and you want to avoid duplicating it, just
create another temporary variable.

THAT is good practice. Not strange gcc-only special code that other
compilers won't touch.

Linus

2004-01-05 04:14:47

by Bill Davidsen

[permalink] [raw]
Subject: Re: GCC 3.4 Heads-up

Linus Torvalds wrote:
>
> On Sun, 4 Jan 2004, Bill Davidsen wrote:
>
>>You pointed out that this generates good code, I pointed out that it
>>also avoids future errors and is not just a trick for broken compilers.
>>I take your point about generating good code, I'm sorry you can't see
>>that avoiding code duplication is good practice even without the benefit
>>of better code.
>
>
> Don't be silly. Using non-standard C is _never_ good practice.

Your example, which I quoted, *is* standard C. And it avoids duplication
of code without extra variables, and is readable. We both agreed it was
standard, why have you canged your mind?

--
bill davidsen <[email protected]>
CTO TMR Associates, Inc
Doing interesting things with small computers since 1979

2004-01-05 04:36:58

by Linus Torvalds

[permalink] [raw]
Subject: Re: GCC 3.4 Heads-up



On Sun, 4 Jan 2004, Bill Davidsen wrote:
>
> Your example, which I quoted, *is* standard C. And it avoids duplication
> of code without extra variables, and is readable. We both agreed it was
> standard, why have you canged your mind?

Oh, that one. I thought you were talking about the gcc extension.

My version is not what I'd call really readable unless you actually have
an agenda to access the variable though a pointer. In fact, the only case
where I have actually seen constructs like that is literally when you want
to avoid a branch for some specific reason, and you do something like
this:

int branchless_code(int *ptr)
{
int dummy;

...
*(ptr ? ptr : &dummy) = value;
...
}

it you'd rather do a unconditional store through a conditional pointer
than have a conditional store, and you use a dummy "sink" variable to take
the store if the condition isn't true.

Some compilers apparently generate this kind of code internally from
conditional statements. I've never seen gcc do it, though.

Linus