Return statement twice in the same expression

N

Nerox

Hi, If i write:

#include <stdio.h>

int foo(int);

int main(void){
int a = 3;
foo(a);
}

int foo(int n){
n > 10 ? return 1 : return 0;
}

This code yields a compilation error, but if i write:

return n > 10 ? 1 : 0;

instead, it works. Why?
What does the standard say about that?

TIA
 
A

Antonio Contreras

Nerox said:
Hi, If i write:

#include <stdio.h>

int foo(int);

int main(void){
int a = 3;
foo(a);
}

int foo(int n){
n > 10 ? return 1 : return 0;
}

This code yields a compilation error, but if i write:

return n > 10 ? 1 : 0;

instead, it works. Why?
What does the standard say about that?

The ternary operator (<expr1> ? <expr2> : <expr3>) is an operator, not
a control structure. [1]

All expressions involved in the ternary operator must yield a value.
The statement "Return x" does not yield a value, in fact it returns
control to the caller function, so there is no one to return a value
to. That's the reason why "n > 10 ? return 1 : return 0" gives
compilation errors.

return n > 10 ? 1 : 0, OTH is perfectly legal. The ternary operator
yields a value that is passed to return.

BTW, in your code it would be totally equivalent, and much cleaner to
simply write:

return n > 10;

[1] It can be used as a control structure. A sentence like:
n > 10 ? a = 1 : a = 0;
would be perfectly legal, but is bad practice. The reason why this is
legal is because an assigment does yield a value (the value being
assigned).
 
E

Eric Sosman

Nerox wrote On 09/21/05 17:03,:
Hi, If i write:

#include <stdio.h>

int foo(int);

int main(void){
int a = 3;
foo(a);
}

int foo(int n){
n > 10 ? return 1 : return 0;
}

This code yields a compilation error, but if i write:

return n > 10 ? 1 : 0;

instead, it works. Why?
What does the standard say about that?

You have not understood the distinction between
"statements" and "expressions" in C. A "statement" can be
understood as an imperative: test a value with `if' and take
different execution paths depending on whether the value is
zero or not, repeat a section of code `while' a value is non-
zero, and so on. One of these imperatives is `return', which
tells C to cease executing the current function and resume
executing its caller, and may also pass a value back so the
caller can use it. The two forms of the imperative `return'
statement are

return;

return _expression_;

.... where the first form simply returns to the caller,
and the second also passes back the value of _expression_.
`n > 10 ? 1 : 0' is the _expression_ in your second
example, and "it works" because this is one of the two
permitted forms of the `return' statement.

An "expression" is a sequence of one or more operands
and zero or more operators, combined according to the
rules of the language. Expressions are not imperative in
the way statements are: they describe a computation that
produces a value, but say very little about how the value
is derived. For example, the expression `f(x) + g(y)'
produces a value that is the sum of `f(x)' and `g(y)', but
doesn't say whether to evaluate `f(x)' before or after
`g(y)'. It just describes the desired value and lets the
compiler figure out how to derive it.

So: can `return' be part of an expression? No, because
it is not an operand and it is not an operator: it makes
exactly as much sense as trying to put `for' or `goto' in
the middle of an expression, to wit, no sense at all. (Not
in C, anyhow; some languages do not distinguish so sharply
between expressions and statements). That's why your first
form yields a compilation error: you've written something
that looks a little bit like an expression, but contains
things that can't appear in expressions.

One source of confusion is that an expression plus a
semicolon can be used wherever a statement is permitted;
this usage is called an "expression statement." When you
see something like `x = 42;' it's tempting to think of it
as an "assignment statement," but it's really an expression
statement made from the expression `x = 42' and the `;'.
The expression happens to contain the assignment operator
`=', and the value produced by the expression (yes, it
produces one) is ignored, but it's really just an ordinary
expression, evaluated in order to achieve the side-effect
of storing a new value in `x'. Some other languages handle
assignment differently: original BASIC, for example, used
`LET X = 42'. In such languages the `=' or `:=' or whatever
is part of the punctuation of the assignment statement (the
way parentheses are part of the punctuation of `while'), but
in C the `=' is a full-fledged operator.

Here are a few more expression statements for you to
ponder -- if you think carefully, you'll realize that they
are all merely expressions and not imperatives, and that
they are all evaluated merely for their side-effects:

++i;

printf("Hello, world!\n");

p = malloc(sizeof *p);

free(p);

The fourth is different from the others in a subtle way.
The first three expressions all produce values that are
ignored: the value of the first is the new value given to
`i', that of the second is the number of characters written
(or EOF if there was an I/O error), that of the third is
the value assigned to `p'. But the fourth produces no value
at all. Some languages distinguish between "functions" that
return values and "subroutines" that do not, but in C there
is no such distinction. Formally (and somewhat artificially)
speaking, the `free' function actually does declare the type
of value it returns -- but that type is `void', and the only
thing you can do with a `void' value is ignore it. This
vacuous `void' type lets C "regularize" itself, in a sense.
Instead of having parallel sets of rules for expressions that
do and don't produce values, C uses just one set of rules and
says that all expressions produce values -- but that some of
the produced values are `void'. (It's reminiscent of a legal
decision some years ago: the court held that an employer's
medical insurance plan did not discriminate against female
employees by failing to provide pregnancy benefits, because
the plan also denied pregnancy benefits to men and thus
treated both sexes equally.)

Summary: Although any expression can be turned into a
statement by appending a `;', no statement can appear as part
of an expression. An expression always produces a value (in
some cases a `void'), but a statement never produces a value
(not even a `void' one).
 
G

Gordon Burditt

int foo(int n){
n > 10 ? return 1 : return 0;
}

This code yields a compilation error, but if i write:

return n > 10 ? 1 : 0;

instead, it works. Why?

You cannot put *ANY* return statement in an expression.
You can, however, put an expression in a return statement.
What does the standard say about that?

A return statement is not an expression, therefore it can't be
mixed with ?: like you tried to in the first set of code above.

Gordon L. Burditt
 
N

Nerox

All expressions involved in the ternary operator must yield a value.
The statement "Return x" does not yield a value, in fact it returns
control to the caller function, so there is no one to return a value
to. That's the reason why "n > 10 ? return 1 : return 0" gives
compilation errors.

int foo(int n){
n > 10 ? bar() : bar();

}

void bar(void)
{
printf("bar call\n");
}

Here, i think bar() doesn't return a value, however the code above
works.
I still don't understand it.
BTW, in your code it would be totally equivalent, and much cleaner to
simply write:

I know, this code is just an example in order to learn.

Thanks again.
 
A

Antonio Contreras

Nerox said:
int foo(int n){
n > 10 ? bar() : bar();

}

void bar(void)
{
printf("bar call\n");
}

Here, i think bar() doesn't return a value, however the code above
works.

Wrong, bar() does return a value. It returns an rvalue of type void.
It's tricky, but there is a subtle but all important difference.
I still don't understand it.


I know, this code is just an example in order to learn.

Thanks again.

You're wellcome.
 
K

Keith Thompson

Nerox said:
int foo(int n){
n > 10 ? bar() : bar();

}

void bar(void)
{
printf("bar call\n");
}

Here, i think bar() doesn't return a value, however the code above
works.
I still don't understand it.

What do you mean when you say it "works"?

Things get a bit confusing when we talk about type void. An
expression can yield a result of type void, except that there are no
values of type void so it doesn't really yield a result at all. Sort
of.

The first operand of the "?:" operator must have scalar type
(something that can be compared to 0 to determine which of the other
two operands to evaluate). There are several legal possibilities for
the types of the second and third operands, one of which is that they
both have void type. The second and third operands' types have to be
closely related to each other, because the result of the whole
expression can be derived from either of them.

The second and third operands can't be return statements because a
return statement is not an expression (not even a void one); it's a
statement. Any expression can be used as a statement by adding a
semicolon, but statements in general cannot be used as expressions.

BTW, I know it's just an example, but you don't have a return
statement in your function foo().
 
P

Peter Nilsson

If there is no prototype of bar in scope, then bar will be presumed
to return an int on C90 implementations. Had you had the void bar(void)
prototype before your definition of foo(), then your compiler would
be required to issue a diagnostic (error/warning) for the constraint
violation.

BTW, foo() does not return a value here.
Wrong, bar() does return a value.

No, it doesn't.
It returns an rvalue of type void.
It's tricky, but there is a subtle but all important difference.

You can prove anything from a false premice.
 
K

Keith Thompson

Peter Nilsson said:
If there is no prototype of bar in scope, then bar will be presumed
to return an int on C90 implementations. Had you had the void bar(void)
prototype before your definition of foo(), then your compiler would
be required to issue a diagnostic (error/warning) for the constraint
violation.

What constraint violation? C99 6.5.15p3 explicitly says that the
second and third operands of a '?:' operator may both have void type.

If he had written

return n > 10 ? bar() : bar();

or otherwise attempted to use the result of the expression, that would
have been a constraint violation.
 
S

Skarmander

Eric Sosman wrote:
You have not understood the distinction between
"statements" and "expressions" in C.

if (a = b) { ...

Neither did K&R. *gets tongue out of cheek*

S.
 
A

Antonio Contreras

Peter said:
If there is no prototype of bar in scope, then bar will be presumed
to return an int on C90 implementations.

Thanks for the nitpick. I assumed that the code posted was just an
example, not executable code. I know that people are encouraged to post
the exact code they have trouble with, but in this case the little
snippet sufficed to show the issue in question.
Had you had the void bar(void)
prototype before your definition of foo(), then your compiler would
be required to issue a diagnostic (error/warning) for the constraint
violation.

I compiled the following code with gcc -W -Wall -ansi -pedantic and got
no error message and no warning:

#include <stdio.h>

void foo (void) {
printf("Foo\n");
}

void bar (void) {
printf("Bar\n");
}

int main (void) {
int n = 10001;

n > 1000 ? foo() : bar();

return 0;
}
BTW, foo() does not return a value here.


No, it doesn't.


You can prove anything from a false premiSe.

True, but this is not the case. Maybe the wording could've been better,
but a void function *has* a return type. Whether you consider that such
function does not return a value or returns a value of type void is a
moot point. The fact is that void types are allowed as the second and
third expressions of a ternary operator.
 
N

Nerox

Peter said:
If there is no prototype of bar in scope, then bar will be presumed
to return an int on C90 implementations.

As Antonio Contreras said that's just an example to show the targeted
problem, don't worry about this at all.

Well, well, now i understand it.
Thank you all, that was a great explanation.
 
L

Lawrence Kirby

On Thu, 22 Sep 2005 00:45:25 -0700, Antonio Contreras wrote:

....
True, but this is not the case. Maybe the wording could've been better,
but a void function *has* a return type. Whether you consider that such
function does not return a value or returns a value of type void is a
moot point. The fact is that void types are allowed as the second and
third expressions of a ternary operator.

Minor nitpick: ? : is called the Conditional operator. It does happen to
be a ternary operator in the same way that / is a binary operator. It also
happens to be the only ternary operator that C has. However "ternary
operator" isn't what defines it, it is just a property that it has.

Lawrence
 
M

Mark B

True, but this is not the case. Maybe the wording could've been better,
but a void function *has* a return type. Whether you consider that such
function does not return a value or returns a value of type void is a
moot point. The fact is that void types are allowed as the second and
third expressions of a ternary operator.

operands, not expressions.
As for the facts:

6.5.15 Conditional operator
...
[#3] One of the following shall hold for the second and
third operands:
-- both operands have arithmetic type;
-- both operands have compatible structure or union types;
-- both operands have void type;
-- both operands are pointers to qualified or unqualified
versions of compatible types;
-- one operand is a pointer and the other is a null
pointer constant; or
-- one operand is a pointer to an object or incomplete
type and the other is a pointer to a qualified or
unqualified version of void.
 
P

Peter Nilsson

Keith said:
What constraint violation? C99 6.5.15p3 explicitly says that the
second and third operands of a '?:' operator may both have void type.

D'oh. I only saw the bold void pertaining to pointers in the PDF copy
of the standard and totally missed the earlier reference to void
operands.

Thanks for the correction.
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top