So according to above statement, is the following code correct?
#include<stdio.h>
int fun()
{
return;
}
int main()
{
printf("%d\n",fun());
return 0;
}
Here, although no useful value is returned by fun(), but can main use
that value in printf()? Will it be UB?
> K&R 2nd edition, page no. 26, says that a function need not return a
> value; a return statement with no
> expression causes control, but no useful value, to be returned to the
> caller......
>
> So according to above statement, is the following code correct?
No. You misunderstand the statement in K&R
A function need not return a value. Those functions that do not return a
value must be declared or defined as returning void. Functions that return
void cannot return a value using the return statement.
Functions that return a value must be declared or defined as returning a
value of a specific type. Functions that return a value of a specific type
must (pedants? am I correct here, or is there an implicit return value?)
return the value using the return statement.
>
> #include<stdio.h>
> int fun()
> {
> return;
> }
> int main()
> {
> printf("%d\n",fun());
> return 0;
> }
>
> Here, although no useful value is returned by fun(), but can main use
> that value in printf()? Will it be UB?
IFAIK, yes.
--
Lew Pitcher
Master Codewright & JOAT-in-training | Registered Linux User #112576
Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.ca/
---------- Slackware - Because I know what I'm doing. ------
> Here, although no useful value is returned by fun(), but can main use
> that value in printf()? Will it be UB?
See C89 6.6.6.4 "The return statement":
"A return statement with an expression shall not appear in a function
whose return type is void. [...] A function may have any number of
return statements, with and without expressions. [...] If a return
statement without an expression is executed, and the value of the
function call is used by the caller, the behavior is undefined."
lacos
He understood it perfectly well.
> A function need not return a value.
True. But K&R specifically say: useful value. They are pragmatists,
unlike the fanatics in this group.
> Those functions that do not return a value must be declared or defined
> as returning void. Functions that return void cannot return a value
> using the return statement.
Read on: the next paragraph says "Since main is a function like any
other, it MAY return a value to its caller" (my emphasis).
It is obvious that what they are saying is that failing to return a
value from a non-void function (or falling off the end of the function)
returns garbage to the caller - whatever happens to be in a certain CPU
register, for example. That is the practical answer.
Or there is the "Heathfield answer": undefined behavior, it probably
reformats your hard disk. A useless, bullshit answer.
One of the reasons K&R are widely regarded as brilliant pedagogues is
precisely because they apply common sense and don't bombard newbies with
a hail of standardese.
Listen to them speak: "Automatic variables for which there is no
explicit initializer have undefined (i.e. garbage) values". How many of
the clc "regulars" would tolerate that inexact but highly informative
parenthesis in their quest for literal exactness?
> On January 12, 2010 14:12, in comp.lang.c, hppym...@yahoo.com wrote:
>
>> K&R 2nd edition, page no. 26, says that a function need not return a
>> value; a return statement with no
>> expression causes control, but no useful value, to be returned to the
>> caller......
>>
>> So according to above statement, is the following code correct?
>
> No. You misunderstand the statement in K&R
>
> A function need not return a value. Those functions that do not return a
> value must be declared or defined as returning void. Functions that return
> void cannot return a value using the return statement.
>
> Functions that return a value must be declared or defined as returning a
> value of a specific type. Functions that return a value of a specific type
> must (pedants? am I correct here, or is there an implicit return value?)
> return the value using the return statement.
A while ago I was thinking about this, and idly wondered about this.
Pure language pedantry: anyone who writes something like this ought to
be shot.
#include <stdio.h>
#include <stdlib.h>
int f(int x) {
if(x)
return 5*x;
printf("Hello\n");
return;
}
int main(void) {
printf("Here is something %d\n",f(10));
f(0);
return EXIT_SUCCESS;
}
--
Online waterways route planner | http://canalplan.eu
Plan trips, see photos, check facilities | http://canalplan.org.uk
"Ersek, Laszlo" wrote:
In ISO/IEC 9899:201x the only return without an expression is
when the function type is a void.
6.8.6.4 The return statement
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.
Regards,
--
Walter Banks
Byte Craft Limited
http://www.bytecraft.com
Thank you Ersek and Lew.
Ersek, just one more doubt. C89 says as above "If a return
statement without an expression is executed, and the value of the
function call is used by the caller, the behavior is undefined."
How can the caller use the value of function call which has a return
statement without an expression?
I mean if I try as in my first program, it shows compile time error.
If I write as
void fun()
{
return ;
}
int main()
{
printf("%d\n",fun());
return 0;
}
Then also it shows error. So how value of fun() can be used when it
has no expression in return statement (although it is UB)?
I don't think he did. At that point, K&R hadn't introduced void
functions.
In fact, it's legal for a non-void function to fall off the end -- but
if the caller attempts to use the result, the behavior is undefined
(C99 6.9.1p12).
In C99, a return statement with an expression may only appear in a
non-void function, and a return statement without an expression may
only appear in a void function (C99 6.8.6.4p1). In C90, which is what
K&R2 describes, a return statement without an expression ("return;")
may appear legally in a non-void function (C90 6.6.6.4).
> A function need not return a value. Those functions that do not return a
> value must be declared or defined as returning void. Functions that return
> void cannot return a value using the return statement.
>
> Functions that return a value must be declared or defined as returning a
> value of a specific type. Functions that return a value of a specific type
> must (pedants? am I correct here, or is there an implicit return value?)
> return the value using the return statement.
There's only an implicit return value in the special case of main, and
that's only in C99.
>>
>> #include<stdio.h>
>> int fun()
>> {
>> return;
>> }
>> int main()
>> {
>> printf("%d\n",fun());
>> return 0;
>> }
>>
>> Here, although no useful value is returned by fun(), but can main use
>> that value in printf()? Will it be UB?
>
> IFAIK, yes.
Yes, that's undefined behavior in C99 (I'm not sure about C90, but
it's certainly a bad idea).
Remember that pre-ANSI C didn't have void, so the usual way to define
a function that doesn't return a useful value was to leave off the
return type, letting it default to int:
do_something() /* implicitly returns int */
{
/* ... */
}
...
do_something(); /* function returns garbage int value,
which is ignored */
In effect, there's an implicit contract between the caller and the
function: the function doesn't return a result, and the caller doesn't
attempt to use it. In pre-ANSI C, there was no way to express or
enforce this contract. ANSI added "void" for this purpose. C90 and
C99 continue to permit falling off the end of a non-void function to
avoid breaking old code like this.
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
It does? I know C99 says that, but I couldn't find the corresponding
text in C90. Can you cite the section number?
> How can the caller use the value of function call which has a return
> statement without an expression?
> I mean if I try as in my first program, it shows compile time error.
>
> If I write as
>
> void fun()
> {
> return ;
> }
>
> int main()
> {
> printf("%d\n",fun());
> return 0;
> }
>
> Then also it shows error. So how value of fun() can be used when it
> has no expression in return statement (although it is UB)?
For example:
#include <stdio.h>
int fun(void)
{
/* no return statement */
}
int main(void)
{
printf("%d\n", fun());
return 0;
> It does? Â I know C99 says that, but I couldn't find the corresponding
> text in C90. Â Can you cite the section number?
I don't have C90 or C89, I was just referring to quote posted by
Ersec.
Thank you Keith to help me understand the concept.
I'm not sure if you meant this, but your code, although written to
behave very differently than Nick's, will probably give the same
value on a lot of systems (since both printf and f return int, and
many systems use a single register for integer return values).
So in regards to Nick's comment about deserving to be shot, his
code could result in a very awful bug indeed! - one that only
appears after the code has been ported, perhaps many years later,
and even then might still exhibit no visible symptoms.
>K&R 2nd edition, page no. 26, says that a function need not return a
>value; a return statement with no
>expression causes control, but no useful value, to be returned to the
>caller......
Early C didn't have void, so functions that didn't have a return value
were declared int (or not declared at all, since that was the default
and there were no prototypes for declaring the argument types) and
didn't specify what should be returned. But that didn't mean you should
*use* the arbitrary value that got returned.
>So according to above statement, is the following code correct?
>
>#include<stdio.h>
>int fun()
>{
> return;
>}
>int main()
>{
> printf("%d\n",fun());
> return 0;
>}
>
>Here, although no useful value is returned by fun(), but can main use
>that value in printf()? Will it be UB?
This is undefined in modern C - much like using a variable with no
value assigned to it. In practice, you will just get some arbitrary
value.
-- Richard
--
Please remember to mention me / in tapes you leave behind.
> fanatics in this group.
> Or there is the "Heathfield answer": undefined behavior, it probably
> reformats your hard disk. A useless, bullshit answer.
I cannot say from whom I've read about such a sentiment in this group
besides you, but he or she was missing advice on algorithms and style
instead of the standards' details. My answer is not targeted
specifically at you; I mean it in general. I'm new here. I'm certain you
don't care why I came here. I'll tell you anyway.
I came here (or first and foremost, c.l.c.m) because I had a specific
question about interpreting the C89 standard that in my opinion required
nit-picking, detail-obsessed "fanatics" (your word) to give a
trustworthy answer. It worked.
I believe this group (and c.l.c.m) is there for interpreting the C
standards. It's there to give advice mostly on *portability*. The only
true sources for bare language level portability are the C89 and C99
standards, and I'm very delighted to have found a place where humans are
willing and skilled enough to help with interpreting those standards.
Anything else I was curious about programming in C on my platform(s) of
choice I was able to find elsewhere on the net. I'm not saying nothing
else should appear here (heck I'm spamming this very group with my views
on SUS all the time), but hostility against the "portability approach"
is exactly missing the point. That very approach is the killer feature
of these two groups.
Re style: I seem to remember an endless flamewar about where to
initialize auto variables. It's a matter of taste.
[To participate in yet another religious debate: I personally find not
only the beginning of an identifier's scope important, but also its end.
Furthermore, I've liked the BSD kernel style's view on initialization of
auto vars. Therefore,
a) In my blocks I have a "list locals" section, then an "initialize
locals" section, then "other" statements. Some auto variables cannot be
initialized without multiple statements, and I don't like a list of
declarations (and since we're talking auto, definitions) with some
objects initialized and some not. Additionally, the SUS likes to say
thing like
The <time.h> header declares the structure timespec, which has
AT LEAST the following members:
time_t tv_sec seconds
long tv_nsec nanoseconds
(emphasis mine). With designated initializers first introduced in C99,
in C89 one cannot portably initialize such objects with an initializer
list (eg. { 1800, 0L } or just { 1800 }.) And then I rather express all
initializations as assignments instead, in one clump.
b) I try to limit the scope (and since we're talkin auto, lifetime) of
objects as narrowly as I can. I not only introduce them as late as
possible but also force them out of scope as early as possible.
{
type_a some_var;
/* compute some_var */
{
type_b some_temp_var;
/* stuff */
some_var = ... some_temp_var ...;
}
func(some_var);
}
This also facilitates the extraction of a compute_some_var(type_a *) or
similar function if needed.]
Re "reformatting the hard disk": AFAICT a user was contemplating
submitting bug reports to multiple compilers because the code he (or
she) inherited crashed on some platforms and did not on some others. It
happened due to undefined behavior. Reporting such phenomena as bugs
might have been an embarrassment for him/her, even though he/she didn't
write the code originally.
Recently, a security vulnerability was found and exploited in the Linux
kernel. The attack vector was to exploit a null pointer dereference
(which is undefined behavior). Masses of programmers came to rely on
their programs crashing with SIGSEGV in response to dereferencing a null
pointer returned by malloc() or something else, so they didn't bother to
check ("the only thing to do would be exiting/aborting anyway"). They
erred.
Undefined behavior should be taken seriously.
> Listen to them speak: "Automatic variables for which there is no
> explicit initializer have undefined (i.e. garbage) values". How many of
> the clc "regulars" would tolerate that inexact but highly informative
> parenthesis in their quest for literal exactness?
"(garbage)" is highly informative in a tutorial context, and inexact in
a reference context. I consider c.l.c(.m) to belong to the reference
kind; in the end, that's why I came here. As said above, everything else
is out there anyway. I don't claim anybody should start learning a
programming language looking at the corresponding standard, just as you
don't learn a natural language by reading the grammar and the dictionary
end to end. But once you find your way in the language, a reference
becomes invaluable.
Insisting on "obscure" details of the standard(s) reflects a painstaking
attitude in programming. C is a sharp tool, you'll cut yourself if
you're not careful. Perhaps not due to an instance of undefined behavior
in your code, but maybe because you're comfortable looking only at Linux
manual or glibc info pages instead of the SUS; and your code will break
on Solaris or OSF/1 (now Tru64) or wherever. If this sounds
condescending, it truly is not; from what I know, your C programming
experience may exceed mine a hundred times -- "you" denotes the generic
"you". Still, no matter the actual standard, details are everything in
C.
I'm only a "fanatic" because I burned myself a few times and got fed up
with it. (Not that I ceased burning myself since I became a "fanatic".)
Sorry for this stupid rant.
... For the record, C89 says in 6.5.7 Initialization: "If an object that
has automatic storage duration is not initialized explicitly, its value
is indeterminate." 3.16 undefined behavior: "Behavior, upon use [...] of
indeterminately valued objects [...]".
C99 6.7.8 Initialization, paragraph 10: "If an object that has automatic
storage duration is not initialized explicitly, its value is
indeterminate." In C99, an indeterminate value does not necessarily
involve undefined behavior; crudely put, it's either an unspecified
(valid) value or a trap representation, and accessing or producing a trap
representation through an lvalue expression is undefined behavior,
unless the expression has character type (3.17.2, 3.17.3, 6.2.6.1).
Thus the following code is undefined behavior in C89, and unspecified in
C99 -- in my interpretation:
{
char c, d;
c = d;
}
Cheers,
lacos
> Ersek, just one more doubt.
(Damn, those Hungarian names. In Hungarian we write Lastname Firstname.
In English that would be Firstname Lastname. Since I use this usenet
client for posting both in Hungarian and English, I figured I'd put
"Lastname, Firstname" because that should be "international" or
whatever, known from alphabetical ordering. So Ersek is my last name.
Just call me lacos if you care. Thanks. And please, PLEASE, avoid the
"Hungarian notation" joke, I'm tired of it.)
> Then also it shows error. So how value of fun() can be used when it
> has no expression in return statement (although it is UB)?
Your original post provided just such an example.
Cheers,
lacos
<snip>
>>> Here, although no useful value is returned by fun(), but can main use
>>> that value in printf()? Will it be UB?
>> IFAIK, yes.
>
> Yes, that's undefined behavior in C99 (I'm not sure about C90, but
> it's certainly a bad idea).
"If a return statement without an expression is executed, and the
value of the function call is used by the caller, the behavior is
undefined." - C89, 3.6.6.4.
<snip>
--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within
<snip>
> Re "reformatting the hard disk": AFAICT a user was contemplating
> submitting bug reports to multiple compilers because the code he (or
> she) inherited crashed on some platforms and did not on some others. It
> happened due to undefined behavior. Reporting such phenomena as bugs
> might have been an embarrassment for him/her, even though he/she didn't
> write the code originally.
Twink's pretence that I would claim that undefined behaviour probably
formats your hard disk is of course just that - a pretence. It is rooted
in two instances of undefined behaviour that I have personally
encountered (not my code in either case, which doesn't mean I'm a coding
saint - it just means I've probably been lucky) and on which I have
reported here in the past.
In the first instance, the cause was failure to allow sufficient room
for a null terminating character, and the result - on a 1989 MS-DOS
system - was that the OS presented a confirmation request along the
lines of "are you sure you want to format your hard disk?" It doesn't
take a huge leap of the imagination to wonder what would have happened
if control had jumped to a very slightly different address. Note that
the hard disk was not actually formatted.
In the second instance, circa 1990-1991, the cause was probably the same
(null termination failure) but I don't honestly remember any more. The
effect was to render a Compaq PC inoperable; we had to dig out Compaq's
diagnostic floppies to resurrect the machine. But the hard disk was not
formatted in this case either.
I know Twink doesn't believe these accounts, but that's his problem, not
mine.
Note that I have seen only two such dramatic outcomes of undefined
behaviour in twenty-plus years of C programming, despite encountering
many, many, many instances of undefined behaviour, and I've never
encountered UB causing a hard disk format. Twink, as usual, is talking
nonsense.
> Recently, a security vulnerability was found and exploited in the Linux
> kernel. The attack vector was to exploit a null pointer dereference
> (which is undefined behavior). Masses of programmers came to rely on
> their programs crashing with SIGSEGV in response to dereferencing a null
> pointer returned by malloc() or something else, so they didn't bother to
> check ("the only thing to do would be exiting/aborting anyway"). They
> erred.
Too right. But it's very difficult to persuade people of that, even in
this group. Do you have a reliable reference to the relevant report? It
may come in handy in the future.
<snip>
> Insisting on "obscure" details of the standard(s) reflects a painstaking
> attitude in programming. C is a sharp tool, you'll cut yourself if
> you're not careful.
Hear, hear.
Interesting. In C89/C90, that's mentioned in the section on return
statements. In C99, the (nearly) equivalent rule is in the section
on function definitions. Except that the C90 rule talks about
executing a return statement without an expression in a non-void
function, something that's a constraint violation in C99. The C99
rule is about reaching the closing "}" of a function definition
without executing a return statement; I don't think C90 addresses
that case (which, I suppose, makes it undefined by default).
>> Recently, a security vulnerability was found and exploited in the Linux
>> kernel. The attack vector was to exploit a null pointer dereference
>> (which is undefined behavior). Masses of programmers came to rely on
>> their programs crashing with SIGSEGV in response to dereferencing a null
>> pointer returned by malloc() or something else, so they didn't bother to
>> check ("the only thing to do would be exiting/aborting anyway"). They
>> erred.
>
> Too right. But it's very difficult to persuade people of that, even in
> this group. Do you have a reliable reference to the relevant report? It
> may come in handy in the future.
Unfortunately, I cannot say which report I've read first (apparently
there are lots of them), and I was also a bit wrong: the null pointer
dereference seems to have happened in kernel space (ie. the "abort
anyway" excuse was not there, I must have recalled that from reddit
where the topic comes up from time to time:
http://www.reddit.com/r/programming/comments/9zc95/handling_outofmemory_conditions_in_c/c0f4lnb
). Nonetheless, a heap of links (leading to even more links):
http://blog.cr0.org/2009/06/bypassing-linux-null-pointer.html
http://www.h-online.com/security/news/item/Hole-in-the-Linux-kernel-allows-root-access-850016.html
http://www.vupen.com/english/advisories/2009/3136
http://blogs.zdnet.com/security/?p=1030 (this is userspace I guess)
http://www.h-online.com/security/news/item/Linux-kernel-vulnerability-fixes-Update-3-742985.html
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-2692
http://www.h-online.com/open/news/item/Critical-vulnerability-in-the-Linux-kernel-affects-all-versions-since-2001-742953.html
Cheers,
lacos
<snip>
>> "If a return statement without an expression is executed, and the
>> value of the function call is used by the caller, the behavior is
>> undefined." - C89, 3.6.6.4.
>>
>> <snip>
>
> Interesting. In C89/C90, that's mentioned in the section on return
> statements. In C99, the (nearly) equivalent rule is in the section
> on function definitions. Except that the C90 rule talks about
> executing a return statement without an expression in a non-void
> function, something that's a constraint violation in C99. The C99
> rule is about reaching the closing "}" of a function definition
> without executing a return statement; I don't think C90 addresses
> that case (which, I suppose, makes it undefined by default).
Sorry, I didn't quite quote enough. The next sentence in C89 is:
"Reaching the } that terminates a function is equivalent to
executing a return statement without an expression."
I gotta start paying more attention. I just read that section
of the C90 standard (6.6.6.4); I don't know how I missed that.
> On January 12, 2010 14:12, in comp.lang.c, hppym...@yahoo.com wrote:
>
> > K&R 2nd edition, page no. 26, says that a function need not return a
> > value; a return statement with no
> > expression causes control, but no useful value, to be returned to the
> > caller......
> >
> > So according to above statement, is the following code correct?
>
> No. You misunderstand the statement in K&R
>
> A function need not return a value. Those functions that do not return a
> value must be declared or defined as returning void. Functions that return
> void cannot return a value using the return statement.
>
> Functions that return a value must be declared or defined as returning a
> value of a specific type. Functions that return a value of a specific type
> must (pedants? am I correct here, or is there an implicit return value?)
> return the value using the return statement.
Not entirely. If you fall off the end of a non-void function, or execute
a return statement without a value in such a function, the Standard
doesn't claim what you return. It does say that _if_ the resulting value
is used by the caller, the behaviour is undefined. When that value is
_not_ used, the behaviour is (presumably, by the rule of exception) just
as defined as if a normal value had been returned.
> > #include<stdio.h>
> > int fun()
> > {
> > return;
> > }
> > int main()
> > {
> > printf("%d\n",fun());
> > return 0;
> > }
> >
> > Here, although no useful value is returned by fun(), but can main use
> > that value in printf()? Will it be UB?
>
> IFAIK, yes.
Yes, but only because the return "value" is used. This:
fun();
would be perfectly defined.
Richard
In C99, a return with no expression ("return;") in a non-void function
is a constraint violation. In C90, it's permitted and equivalent to
falling off the end of the function.
It's not written to behave in any particular way at all, as it's a
contraint violation.
>, will probably give the same
> value on a lot of systems (since both printf and f return int, and
> many systems use a single register for integer return values).
>
> So in regards to Nick's comment about deserving to be shot, his
> code could result in a very awful bug indeed! - one that only
> appears after the code has been ported, perhaps many years later,
> and even then might still exhibit no visible symptoms.
Nope, it should appear immediately upon seeing an inability to
compile without the obligatory diagnostic.
Phil
--
Any true emperor never needs to wear clothes. -- Devany on r.a.s.f1
Not in C90. (Of course it's horrible style in either C90 or C99.)
[snip]
> Phil Carmody <thefatphi...@yahoo.co.uk> writes:
>> Andrew Poelstra <apoe...@localhost.localdomain> writes:
>>> On 2010-01-12, Stefan Ram <r...@zedat.fu-berlin.de> wrote:
>>>> Nick <3-no...@temporary-address.org.uk> writes:
>>>>>int f(int x) {
>>>>> if(x)
>>>>> return 5*x;
>>>>> printf("Hello\n");
>>>>> return;
>>>>>}
>>>>
>>>> int f( int const x ){ return x ? 5 * x : printf( "Hello\n" ); }
>>>>
>>>
>>> I'm not sure if you meant this, but your code, although written to
>>> behave very differently than Nick's
>>
>> It's not written to behave in any particular way at all, as it's a
>> contraint violation.
>
> Not in C90. (Of course it's horrible style in either C90 or C99.)
But does it (mine) exhibit undefined behaviour? I didn't know that a
bare return was a constraint violation in C99 (which is nice to know) but
feel free to remove the return at the end of the function as falling off
the end still works.
Horribleness not just conceded, but gloried in.
The function f by itself, even with the bare "return;" deleted and
allowing it to fall off the end, exhibits no behavior at all, since
it's never called. That's not as picky as it sounds; the manner in
which it's called is relevant here.
A simpler example that illustrates the same point:
int f(void)
{
puts("In f");
}
If the caller doesn't use the (nonexistent) result, there's no problem.
int main(void)
{
f();
return 0;
}
If the caller does attempt to use the result, as in:
int i = f();
then the behavior is undefined, by C99 6.9.1p12:
If the } that terminates a function is reached, and the value of
the function call is used by the caller, the behavior is
undefined.
and by C90 6.6.6.4:
If a return statement without an expression is executed, and the
value of the function call is used by the caller, the behavior
is undefined. Reaching the } that terminates a function is
equivalent to executing a return statement without an expression.
--
It did - I'd missed the fact that the main had got snipped, sorry!
The main function called f twice, like this:
printf("Result: %d\n",f(1));
f(0);
>
> A simpler example that illustrates the same point:
>
> int f(void)
> {
> puts("In f");
> }
>
> If the caller doesn't use the (nonexistent) result, there's no problem.
>
> int main(void)
> {
> f();
> return 0;
> }
>
> If the caller does attempt to use the result, as in:
>
> int i = f();
>
> then the behavior is undefined, by C99 6.9.1p12:
>
> If the } that terminates a function is reached, and the value of
> the function call is used by the caller, the behavior is
> undefined.
>
> and by C90 6.6.6.4:
>
> If a return statement without an expression is executed, and the
> value of the function call is used by the caller, the behavior
> is undefined. Reaching the } that terminates a function is
> equivalent to executing a return statement without an expression.
Which means, I think, that a function that sometimes returns a value and
sometimes doesn't is perfectly all right as long as the different
behaviours match the appropriate calls.
Yes. Well, it's "perfectly all right" in the sense that its behavior
is well defined. As a matter of programming style, either it should
always return a value or it should be two different functions.