Conditional operator using void expression

D

Dan Henry

I have run across functions in the Linux kernel's MTD driver that have
me scratching my head a bit. The functions have the general form:

extern int bar(size_t len, size_t *retlen, unsigned char *buf);

int foo(size_t len, unsigned char *buf) {
size_t retlen;
int ret;

ret = bar(len, &retlen, buf);
return ret ? : retlen; /* <-- void expression and UB? */
}

It is foo()'s return statement that I am soliciting comments about. Am
I correct that the conditional operator's second operand is a void
expression and if so, doesn't that invoke undefined behavior by
attempting to use the value of a void expression? I sometimes
struggle interpreting the standard and hope I haven't overlooked
something, but I can't find the verse that might bless the statement.
If it is allowed, what value would foo() return for nonzero ret --
zero?

Thanks,
 
I

Ian Collins

Dan said:
I have run across functions in the Linux kernel's MTD driver that have
me scratching my head a bit. The functions have the general form:

extern int bar(size_t len, size_t *retlen, unsigned char *buf);

int foo(size_t len, unsigned char *buf) {
size_t retlen;
int ret;

ret = bar(len, &retlen, buf);
return ret ? : retlen; /* <-- void expression and UB? */
}

It is foo()'s return statement that I am soliciting comments about. Am
I correct that the conditional operator's second operand is a void
expression and if so, doesn't that invoke undefined behavior by
attempting to use the value of a void expression? I sometimes
struggle interpreting the standard and hope I haven't overlooked
something, but I can't find the verse that might bless the statement.
If it is allowed, what value would foo() return for nonzero ret --
zero?
I think it's a syntax error, but gcc accepts it without complaint in
default mode. It does warn in strict mode:

gcc -Wall -pedantic -ansi x.c
x.c: In function `foo':
x.c:11: warning: ISO C forbids omitting the middle term of a ?: expression

I guess Linux kernel hackers don't use strict mode :)
 
K

Keith Thompson

Dan Henry said:
I have run across functions in the Linux kernel's MTD driver that have
me scratching my head a bit. The functions have the general form:

extern int bar(size_t len, size_t *retlen, unsigned char *buf);

int foo(size_t len, unsigned char *buf) {
size_t retlen;
int ret;

ret = bar(len, &retlen, buf);
return ret ? : retlen; /* <-- void expression and UB? */
}

It is foo()'s return statement that I am soliciting comments about. Am
I correct that the conditional operator's second operand is a void
expression and if so, doesn't that invoke undefined behavior by
attempting to use the value of a void expression?
[...]

No, it's not a void expression. A void expression would be an
expression of type void, such as (void)42. What appears between the
'?' and ':' is an empty token sequence, and is not an expression at
all. As far as standard C is concerned, it's simply a syntax error.

As an extension, gcc allows the middle operand of the conditional
operator to be omitted; see the gcc documentation for details. This
is a permissible extension, since it doesn't affect the behavior of
any strictly conforming program.

gcc with the "-pedantic" option correctly issues a warning for this.
 
R

Robert Gamble

I have run across functions in the Linux kernel's MTD driver that have
me scratching my head a bit. The functions have the general form:

extern int bar(size_t len, size_t *retlen, unsigned char *buf);

int foo(size_t len, unsigned char *buf) {
size_t retlen;
int ret;

ret = bar(len, &retlen, buf);
return ret ? : retlen; /* <-- void expression and UB? */

}

It is foo()'s return statement that I am soliciting comments about. Am
I correct that the conditional operator's second operand is a void
expression and if so, doesn't that invoke undefined behavior by
attempting to use the value of a void expression?

It's not a void expression, it's the lack of an expression. It isn't
valid Standard C but is a gcc extension in which:
x ? : y;
is treated as:
x ? x : y;

It's a useful extension but it isn't Standard.

Robert Gamble
 
S

santosh

Dan said:
I have run across functions in the Linux kernel's MTD driver that have
me scratching my head a bit. The functions have the general form:

extern int bar(size_t len, size_t *retlen, unsigned char *buf);

int foo(size_t len, unsigned char *buf) {
size_t retlen;
int ret;

ret = bar(len, &retlen, buf);
return ret ? : retlen; /* <-- void expression and UB? */
}

It is foo()'s return statement that I am soliciting comments about. Am
I correct that the conditional operator's second operand is a void
expression and if so, doesn't that invoke undefined behavior by
attempting to use the value of a void expression? I sometimes
struggle interpreting the standard and hope I haven't overlooked
something, but I can't find the verse that might bless the statement.
If it is allowed, what value would foo() return for nonzero ret --
zero?

Thanks,

In general the Linux kernel makes unapolegetic use of gcc's
extensions, of which this is one. It a form of shortcut that evaluates
to:

return ret ? ret : retlen;
 
C

CBFalconer

Robert said:
.... snip ...

It's not a void expression, it's the lack of an expression. It
isn't valid Standard C but is a gcc extension in which:
x ? : y;
is treated as:
x ? x : y;

It's a useful extension but it isn't Standard.

As far as I am concerned, using it is extremely sloppy programming
when portable programming would only require one extra identifier.
It's all very well to use extensions when they actually help, but
stupid when they are unnecessary.
 
D

Dan Henry

Dan Henry said:
I have run across functions in the Linux kernel's MTD driver that have
me scratching my head a bit. The functions have the general form:

extern int bar(size_t len, size_t *retlen, unsigned char *buf);

int foo(size_t len, unsigned char *buf) {
size_t retlen;
int ret;

ret = bar(len, &retlen, buf);
return ret ? : retlen; /* <-- void expression and UB? */
}

It is foo()'s return statement that I am soliciting comments about. Am
I correct that the conditional operator's second operand is a void
expression and if so, doesn't that invoke undefined behavior by
attempting to use the value of a void expression?
[...]

No, it's not a void expression. A void expression would be an
expression of type void, such as (void)42. What appears between the
'?' and ':' is an empty token sequence, and is not an expression at
all. As far as standard C is concerned, it's simply a syntax error.

As an extension, gcc allows the middle operand of the conditional
operator to be omitted; see the gcc documentation for details. This
is a permissible extension, since it doesn't affect the behavior of
any strictly conforming program.

gcc with the "-pedantic" option correctly issues a warning for this.

Ian, Keith, Robert, and santosh:

Thank you all for your gentle guidance. I am not often fooled by
GCC-isms, but that *gratuitous* extension caught me thinking that I
had missed some corner-case of language usage.

I have emphasized *gratuitous* above because, in my opinion, that
extension (if limited to that bit of functionality, and I'll be
looking it up tomorrow to see if it is that limited) offers very
little or perhaps even negative benefit if one factors in the cost of
having to think about it even being an extension -- but that's just
me.

[Ranting OT rhetorical question]
I can appreciate some GCC-isms in the context of "the kernel" easing
some things, but really now, is eliminating/shorthanding the second
operand *that* useful?
[/Ranting OT rhetorical question]
 
M

Mike King

Man, you guys are brutal! "obdurate" is the word of the day that comes to
mind... How often does a "legit" post come along?
 
S

santosh

Mike King wrote:

[top-post fixed]
Man, you guys are brutal! "obdurate" is the word of the day that comes to
mind... How often does a "legit" post come along?

As far as I can see, nobody is criticising the OP for his genuine
mistake. Also I should probably warn you that you'll shortly be
advised not to top-post.
 
K

Keith Thompson

Dan Henry said:
Thank you all for your gentle guidance. I am not often fooled by
GCC-isms, but that *gratuitous* extension caught me thinking that I
had missed some corner-case of language usage.

I have emphasized *gratuitous* above because, in my opinion, that
extension (if limited to that bit of functionality, and I'll be
looking it up tomorrow to see if it is that limited) offers very
little or perhaps even negative benefit if one factors in the cost of
having to think about it even being an extension -- but that's just
me.

[Ranting OT rhetorical question]
I can appreciate some GCC-isms in the context of "the kernel" easing
some things, but really now, is eliminating/shorthanding the second
operand *that* useful?
[/Ranting OT rhetorical question]

Quoting the gcc documentation:

In this simple case, the ability to omit the middle operand is not
especially useful. When it becomes useful is when the first
operand does, or may (if it is a macro argument), contain a side
effect. Then repeating the operand in the middle would perform
the side effect twice. Omitting the middle operand uses the value
already computed without the undesirable effects of recomputing
it.

I'm not necessarily arguing that the Linux kernel *should* use this
particular extension, but since the decision has already been made to
use gcc-specific features (to the extent that compiling the kernel
with anything other than gcc is nearly impossible), I suppose it's
just a matter of the kernel being written in GNU-C rather than C.

(I think Intel's icc can also compile the kernel, but a lot of effort
has been put into making it gcc-compatible.)
 
J

jaysome

Man, you guys are brutal! "obdurate" is the word of the day that comes to
mind... How often does a "legit" post come along?

Admonishing sloppy programming, which is arguably what the OP's
example constituted, should not be labeled "obdurate". Just as
admonishing top-posting should not be labeled "obdurate" (awkward
context as a result of your top-posting follows).
[snip]
As far as I am concerned, using it is extremely sloppy programming
when portable programming would only require one extra identifier.
It's all very well to use extensions when they actually help, but
stupid when they are unnecessary.
 
F

Flash Gordon

santosh wrote, On 27/02/07 06:27:
Mike King wrote:

[top-post fixed]
Man, you guys are brutal! "obdurate" is the word of the day that comes to
mind... How often does a "legit" post come along?

The OPs posts have been "legit". The OP asked about something he thought
must be standard C, and this is the right place for that, and has
accepted the the expert advice that it is not standard C. The OP even
went on to express an opinion about the use of such extensions that I
believe many of the regulars here (including me) would agree with.
As far as I can see, nobody is criticising the OP for his genuine
mistake.

I would say that the OPs mistake in assuming it was standard C was
entirely understandable so I think it unlikely that the OP will be
criticised by those it is worth reading here.
> Also I should probably warn you that you'll shortly be
advised not to top-post.

OK, we can't have you being mistaken about such a thing.

Mike, please don't top post, your reply belongs after (or interspersed
with the text you are replying to. See most of the posts in this group
for examples including the one you were replying to.
 
R

Richard Tobin

Keith Thompson said:
Quoting the gcc documentation:

In this simple case, the ability to omit the middle operand is not
especially useful. When it becomes useful is when the first
operand does, or may (if it is a macro argument), contain a side
effect. Then repeating the operand in the middle would perform
the side effect twice. Omitting the middle operand uses the value
already computed without the undesirable effects of recomputing
it.

I don't find this very convincing. The usual reason for macros of this
kind is efficiency, and the usual reason for using them rather than
inline functions is portability to systems that don't provide them.
Since GCC does support inline functions, using a different GCC-specific
mechanism is pointless.

-- Richard
 
Y

Yevgen Muntyan

Mike said:
Man, you guys are brutal! "obdurate" is the word of the day that comes to
mind...

It happens, nevermind.
How often does a "legit" post come along?

Not very often. Usually when it is "how do I return
a char array from function" or similar. And you
better don't top-post here, it's dangerous, can invoke
undefined behavior of some regulars.

[snip essay about sloppiness and happiness]

Best regards,
Yevgen
 
Y

Yevgen Muntyan

Richard said:
I don't find this very convincing. The usual reason for macros of this
kind is efficiency, and the usual reason for using them rather than
inline functions is portability to systems that don't provide them.
Since GCC does support inline functions, using a different GCC-specific
mechanism is pointless.

return foo() ? : bar;

It's not only about macros. Of course one always can introduce
a helper variable here and everything (of course one can use
standard C), that's another thing.

Yevgen
 
K

Keith Thompson

Yevgen Muntyan said:
return foo() ? : bar;

It's not only about macros. Of course one always can introduce
a helper variable here and everything (of course one can use
standard C), that's another thing.

Yes, that's a good example. If the ability to omit the middle operand
were specified in the standard, I wouldn't hesitate to use the
feature. It's not a critical feature, in that there are easy ways to
avoid it, but it is a nice notational convenience once you understand
how it works. If I'd been voting on features to add to the language,
I probably would have picked this one before allowing trailing commas
in enumerations.

I'm not advocating adding this to the standard; I wouldn't mind if it
were added, but I understand the dangers of creeping featurism. (And
if it were added to C200Y, or C201Z, it would be many years before we
could count on it being universally implemented.) But if you're
writing code that's absolutely dependent on a specific compiler and
its extensions, you might as well use them.
 

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
473,995
Messages
2,570,236
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top