what value does lack of return or empty "return;" return

G

Greenhorn

Hi,
when a function doesn't specify a return type ,value what value is
returned. In the below programme, the function sample()is returning the
value passed to 'k'.

sample(int);
main()
{
int i = 0,j;
j = sample(0);
printf("%d", j);
getch();
}

sample(k)
{
return;
}
 
A

Artie Gold

Greenhorn said:
Hi,
when a function doesn't specify a return type ,value what value is
returned. In the below programme, the function sample()is returning the
value passed to 'k'.

sample(int);
main()
{
int i = 0,j;
j = sample(0);
printf("%d", j);
No declaration? (Hint: what are you including?)
getch(); No such thing.
}

sample(k)
{
return;
}
It's undefined behavior. Could be anything. Or nasal demons might ensue.
(The only exception is that `main()' returns 0 in C99 if no value is
explicitly returned. You're not using C99; your program would have been
rejected for trying to use implicit int.)

Turn up the warning level on your compiler!

HTH,
--ag
 
K

Kevin Bracey

In message <[email protected]>
Artie Gold said:
It's undefined behavior. Could be anything. Or nasal demons might ensue.
(The only exception is that `main()' returns 0 in C99 if no value is
explicitly returned. You're not using C99; your program would have been
rejected for trying to use implicit int.)

It would also have been rejected for that return - a "return" without a value
where one is required is now a constraint violation in C99.
 
A

Artie Gold

Kevin said:
In message <[email protected]>



It would also have been rejected for that return - a "return" without a value
where one is required is now a constraint violation in C99.
Would it have gotten that far? Seems to me it wouldn't even parse.

--ag
 
K

Keith Thompson

Artie Gold said:
Would it have gotten that far? Seems to me it wouldn't even parse.

"return;" is perfectly legal in a function returning void. It's
a semantic error, not a syntax error.
 
A

Artie Gold

Keith said:
"return;" is perfectly legal in a function returning void. It's
a semantic error, not a syntax error.
Of course. But it's either a function returning int in C89 or nonsense
(no return type) in C99. That's what I referring to in my `wouldn't even
parse' comment.

Cheers,
--ag
 
K

Keith Thompson

Artie Gold said:
Of course. But it's either a function returning int in C89 or nonsense
(no return type) in C99. That's what I referring to in my `wouldn't
even parse' comment.

The term "parse" refers specifically to *syntactic* analysis.
 
A

Artie Gold

Keith said:
Artie Gold said:
Keith said:
Artie Gold <[email protected]> writes:
[...]
Would it have gotten that far? Seems to me it wouldn't even parse.

"return;" is perfectly legal in a function returning void. It's
a semantic error, not a syntax error.

Of course. But it's either a function returning int in C89 or nonsense
(no return type) in C99. That's what I referring to in my `wouldn't
even parse' comment.


The term "parse" refers specifically to *syntactic* analysis.
Exactly.

And and it seems to me that:

sample(k)
{
return;
}

would choke on either the `(' or the `{'.

Cheers,
--ag
 
A

Artie Gold

Artie said:
Keith said:
Artie Gold said:
Keith Thompson wrote:


[...]

Would it have gotten that far? Seems to me it wouldn't even parse.


"return;" is perfectly legal in a function returning void. It's
a semantic error, not a syntax error.


Of course. But it's either a function returning int in C89 or nonsense
(no return type) in C99. That's what I referring to in my `wouldn't
even parse' comment.



The term "parse" refers specifically to *syntactic* analysis.
Exactly.

And and it seems to me that:

sample(k)
{
return;
}

would choke on either the `(' or the `{'.

Cheers,
--ag
Actually, I take that back -- `sample' itself would make no sense in
that context (it's not a type).

--ag
 
K

Keith Thompson

Artie Gold said:
Exactly.

And and it seems to me that:

sample(k)
{
return;
}

would choke on either the `(' or the `{'.

I feel like we're arguing over the most trivial aspect of this, but ...

Parsing is based on the language grammar. The above is an old-style
definition, but let's make it explicit:

int sample(int k)
{
return;
}

The "return;" is invalid because it doesn't return a value. But this
is perfectly legal:

void sample(int k)
{
return;
}

The *parser*, when it see the "return;", doesn't remember what type
the containing function returns. The distinction between a valid
"return;" in a void function, and an invalid "return;" in an int
function, cannot be made by the parser. It can only be made during
semantic analysis.

Conceivably the grammar could have been defined with one syntax for a
void function definition (allowing "return;") and another for a
non-void function definition (disallowing "return;"). Fortunately,
this wan't necessary, since it's easy enough to detect the error
semantically.

In C99, this restriction is expressed as a constraint in 6.8.6.4p1:

A return statement with an expression shall not appear in a
function whose return type is void. A return statement without an
expression shall only appear in a function whose return type is
void.

In C90, a "return;" in a non-void function is allowed (a throwback to
K&R C, which didn't have void functions), but an attempt to use the
function result causes undefined behavior.

Incidentally, this is a distinction that the standard does not
(clearly) make. Both syntactic and semantic analysis occur during
translation phase 7. An implementation is free to mix the two in any
way it likes.
 
W

Walter Roberson

:The *parser*, when it see the "return;", doesn't remember what type
:the containing function returns. The distinction between a valid
:"return;" in a void function, and an invalid "return;" in an int
:function, cannot be made by the parser. It can only be made during
:semantic analysis.

:In C99, this restriction is expressed as a constraint in 6.8.6.4p1:

: A return statement with an expression shall not appear in a
: function whose return type is void. A return statement without an
: expression shall only appear in a function whose return type is
: void.

That's mostly detectable syntactically. One can do syntactic analysis
to determine whether one is inside a function definition or not,
inside a comment or not, inside an #define. Then the presence
of the word 'void' followed by an identifier followed by
one of the argument declaration forms, followed by a '{' intead of
a ';', places one -syntactically- inside a void function. At that
point, whether 'return' is followed by something other than ';'
is a matter of syntax.

I say "mostly detectable" because one can do all kinds of perverse
things with the preprocessor that cannot be syntactically detected
until after one has undergone semantic translation of the preprocessor
directives. Even excluding #define that expand to syntactic elements,
there is the issue of #if's that do not enclose balanced {}.

Also, even without #if and #define, it cannot be syntactically
detected by a simple standard regular expression, deterministic
FSA or non-deterministic FSA (all of which are, of course, equivilent
in expressive power), because standard RE's and FSA cannot handle
the necessary {} matching or "" matching. A simple push-down
automata can handle it, though, in the absence of preprocessor
managling.
 
K

Keith Thompson

:The *parser*, when it see the "return;", doesn't remember what type
:the containing function returns. The distinction between a valid
:"return;" in a void function, and an invalid "return;" in an int
:function, cannot be made by the parser. It can only be made during
:semantic analysis.

:In C99, this restriction is expressed as a constraint in 6.8.6.4p1:

: A return statement with an expression shall not appear in a
: function whose return type is void. A return statement without an
: expression shall only appear in a function whose return type is
: void.

That's mostly detectable syntactically. One can do syntactic analysis
to determine whether one is inside a function definition or not,
inside a comment or not, inside an #define.

Comments are eliminated in translation phase 3; #defines vanish in
phase 4. Parsing (syntactic analysis) doesn't occur until phase 7, so
the parser will never see either comments or #defines.

Certainly the parser "knows" whether it's inside a function definition
(so a statement outside a function definition, for example, is a
syntax error).
Then the presence
of the word 'void' followed by an identifier followed by
one of the argument declaration forms, followed by a '{' intead of
a ';', places one -syntactically- inside a void function. At that
point, whether 'return' is followed by something other than ';'
is a matter of syntax.

If you look at the syntax definition for a function-definition:

function-definition:
declaration-specifiers declarator declaration-list(opt) compound-statement
declaration-list:
declaration
declaration-list declaration

you'll see that it doesn't distinguish between void and non-void
functions.

To illustrate how one implementation does this (though of course that
doesn't prove anything about the standard):

% cat tmp.c
int foo(void)
{
return; /* line 3 */
}

return; /* line 6 */
% gcc -c -std=c99 tmp.c
tmp.c: In function `foo':
tmp.c:3: warning: `return' with no value, in function returning non-void
tmp.c: At top level:
tmp.c:6: error: parse error before "return"

The return statement outside the function definition causes a parse
error; the one inside the function definition is a semantic error.
 
C

CBFalconer

Keith said:
.... snip ...

If you look at the syntax definition for a function-definition:

function-definition:
declaration-specifiers declarator declaration-list(opt) compound-statement
declaration-list:
declaration
declaration-list declaration

you'll see that it doesn't distinguish between void and non-void
functions.

Which is probably due to the BNF specified in the standard (haven't
checked). However there is no reason the parsing code cannot
differentiate and yield errors, nor that the BNF cannot be written
to separate functions and 'procedures'. In practice the freedom to
reorder components in the source (static const int vs const static
int etc.) makes this awkward. C has too many ways to arrive at the
same place.
 
C

Chris Torek

Keith said:
If you look at the [C89 or C99] syntax definition for a
function-definition ... you'll see that it doesn't distinguish
between void and non-void functions.

[He goes on to note that this is one reason C compilers treat
"return without a value in a non-void function" as a semantic error
rather than a syntactic one.]

Which is probably due to the BNF specified in the standard (haven't
checked).

That is what Keith Thompson just said. :) The syntax in the
C standards is specified that way.
However there is no reason the parsing code cannot
differentiate and yield errors, nor that the BNF cannot be written
to separate functions and 'procedures'. In practice the freedom to
reorder components in the source (static const int vs const static
int etc.) makes this awkward. C has too many ways to arrive at the
same place.

Indeed, this is true for C99. For C89, however, "return without a
value" *is* allowed, even in a non-void function:

double f(int *ip) {
if (ip != NULL) {
*ip = 1;
return;
}
return 3.1415926535897932384626433832795;
}

is a legal (albeit rather pointless) C89 function, which can be
called from code such as:

void g(void) {
int x;
double y;

f(&x);
y = f(NULL);
}

If you wish to accept syntactically-valid C89 code, then, you cannot
make "return without a value in non-void function" into the kind
of error that changes code-generation (syntax errors usually suppress
it entirely, or at the least, remove a few needed nodes from the
parse tree, so that wrong code will come out of the back end of
the compiler).

(Note that C compilers are always allowed to produce diagnostics,
even spurious ones, so:

foo.c, line 3: warning: in function f(): return without a value,
in function with return type "double"

is allowed, even in C89, even though the code is technically OK,
however ugly it may be.)
 
W

Walter Roberson

|> In article <[email protected]>,
|> :The *parser*, when it see the "return;", doesn't remember what type
|> :the containing function returns. The distinction between a valid
|> :"return;" in a void function, and an invalid "return;" in an int
|> :function, cannot be made by the parser. It can only be made during
|> :semantic analysis.

|> Then the presence
|> of the word 'void' followed by an identifier followed by
|> one of the argument declaration forms, followed by a '{' intead of
|> a ';', places one -syntactically- inside a void function. At that
|> point, whether 'return' is followed by something other than ';'
|> is a matter of syntax.


|If you look at the syntax definition for a function-definition:

|you'll see that it doesn't distinguish between void and non-void
|functions.

If you look at what you wrote, you said that certain kinds of
validity checks on 'return' statements "cannot be made by the
parser" and "can only be made during semantics analysis".

I showed that this is incorrect: that once past preprocessing,
a parser *could* syntatically determine whether a void function
had a non-void return.

I did not say that a parser -must- so determine, and I didn't
say that there was a distinction at the BNF level: I just pointed
out that the recognition *could* be made by the parser.

If you had written that the distinction "is not" made by the parser
then you would be talking about implimentation, and might be correct
for all existing parsers -- but you wrote "cannot", which means
"not possible", and I showed that at least part of it is possible.
 
K

Keith Thompson

If you had written that the distinction "is not" made by the parser
then you would be talking about implimentation, and might be correct
for all existing parsers -- but you wrote "cannot", which means
"not possible", and I showed that at least part of it is possible.

Ok, it's possible.

My original point was to refute someone else's statement that a
"return;" in a non-void function "wouldn't even parse". In fact it
could, and almost certainly would. I got a little carried away in
implying that it *must* parse.

You're right, a C99 compiler (but not a C90 compiler) *could* use
separate grammar productions for void and non-void function
definitions, and thereby catch "return;" as a syntax error. (There's
no requirement for a compiler to use the grammar in the standard, as
long as it uses one that lets it catch errors and process correct
code.) It would require some extra work for the case of a function
whose return type is a typedef for void, but that shouldn't be any
more difficult than typedef handling in general.

It would be a perverse implementation. Semantic errors are easier to
handle within the compiler than syntax errors. For a semantic error,
the compiler can just issue a diagnostic, set a flag indicating that
the compilation will fail, and move on; for a syntax error, it has to
either reconstruct a guessed valid parse so it can continue
processing, or give up and die.
 

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,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top