function not returning a value

H

happy

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?

#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?
 
L

Lew Pitcher

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.
 
E

Ersek, Laszlo

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
 
A

Antoninus Twink

No. You misunderstand the statement in K&R

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?
 
W

Walter Banks

Ersek said:
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."

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,
 
N

Nick

Lew Pitcher said:
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;
}
 
K

Keith Thompson

Lew Pitcher said:
No. You misunderstand the statement in K&R

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.
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.
 
H

happy

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

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)?
 
K

Keith Thompson

happy said:
happy said:
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."

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."

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;
}
 
H

happy

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.
 
A

Andrew Poelstra

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, 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.
 
R

Richard Tobin

happy said:
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
 
E

Ersek, Laszlo

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
 
E

Ersek, Laszlo

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
 
K

Keith Thompson

Richard Heathfield said:
"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).
 
E

Ersek, Laszlo

Ersek, Laszlo wrote:

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/i...l-affects-all-versions-since-2001-742953.html

Cheers,
lacos
 
K

Keith Thompson

Richard Heathfield said:
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.
 
R

Richard Bos

Lew Pitcher said:
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.
IFAIK, yes.

Yes, but only because the return "value" is used. This:

fun();

would be perfectly defined.

Richard
 
K

Keith Thompson

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.
[...]

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.
 

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,755
Messages
2,569,536
Members
45,008
Latest member
HaroldDark

Latest Threads

Top