A value returned to a function without a `return' statement, why?

L

lovecreatesbeauty

I ever missed a `return' statement when write a function `int
HighDigit(Num)' to get the highest digit of an integer.

But even if the `return' statement is ignored the function still can
obtain an `correct' return value when the argument `Num' is larger than
or equal to the Macro `NUM_SYS'.

If the argument is less than the Macro, the function without a `return'
get an undefined value. I've made a test on Ms Windows 2000 and VC 6.


Thank you in advance for explaining why.

And would you please comment on this algorithm? Thank you.




i.e.
Num HighDigit(Num)
======================
123 | 1
321 | 3
2 | 2
10 | 1
______________________





The code I write is:


//highdigit.h

#ifndef _HIGH_DIGIT_H_
#define _HIGH_DIGIT_H_

#define NUM_SYS 10 //number system, decimal assumed as default

int HighDigit(int Num);

#endif //_HIGH_DIGIT_H_


//highdigit.c

#include "highdigit.h"

int HighDigit(int Num){
while (Num >= NUM_SYS){
Num /= NUM_SYS;
}

//return Num; //This statement be missed by me at first.
}
 
J

Jack Klein

I ever missed a `return' statement when write a function `int
HighDigit(Num)' to get the highest digit of an integer.

It is actually legal in C to omit a return statement from a function
with a return type other than void. Rather foolish, but legal.
But even if the `return' statement is ignored the function still can
obtain an `correct' return value when the argument `Num' is larger than
or equal to the Macro `NUM_SYS'.

Now here the C standard does have something to say. If you miss a
return statement in a function that has a non-void return type, and if
the calling code uses the return value in any way, then the behavior
is undefined.
If the argument is less than the Macro, the function without a `return'
get an undefined value. I've made a test on Ms Windows 2000 and VC 6.

Actually the result is always undefined, a term with a precisely
defined meaning in the C language. It is just in some cases the value
is what you expect it to be, and in other cases it is not.
Thank you in advance for explaining why.

When you produce undefined behavior, the C language no longer
specifies what will happen. One possible result of undefined behavior
is that, in some cases, the program "works" the way you think it
should.
And would you please comment on this algorithm? Thank you.




i.e.
Num HighDigit(Num)
======================
123 | 1
321 | 3
2 | 2
10 | 1
______________________





The code I write is:


//highdigit.h

#ifndef _HIGH_DIGIT_H_
#define _HIGH_DIGIT_H_

This is something you should not do. All identifiers beginning with
two underscores or an underscore followed by an uppercase letter are
reserved for the compiler, and not to be used in your code.
#define NUM_SYS 10 //number system, decimal assumed as default

Either your function always works with base 10, in which case you
don't need the definition in the header but only in the source code
file with the function body. And it is not a default, it is the only
value. Or you want it to work on various bases, in which case the
base should be a function parameter as in functions like strtol() in
the standard library.
int HighDigit(int Num);

You could make this:

int HighDigit(int Num, int base);
#endif //_HIGH_DIGIT_H_


//highdigit.c

#include "highdigit.h"

int HighDigit(int Num){
while (Num >= NUM_SYS){
Num /= NUM_SYS;
}

//return Num; //This statement be missed by me at first.
}

....and likewise:

int HighDight(int Num, int base)
{
assert(base > 0);
while (Num >= base)
{
Num /= base;
}
return Num;
}
 
L

lovecreatesbeauty

Jack, thank you. Could please give some suggestion on the usage of
`assert()'.

I think, an runtime value makes assert() failed in debug version can
also (always) make it failed in release version, but in the release
version (NDEBUG defined) the `assert()' means null, so it can't catch
runtime error in release version.
 
S

Stephen Sprunk

Jack Klein said:
When you produce undefined behavior, the C language no longer
specifies what will happen. One possible result of undefined behavior
is that, in some cases, the program "works" the way you think it
should.

As to why the UB leads to it "working" in his case (as the OP asked), it may
be because the compiler happened to use the same register for "Num" that is
also the return value register. Of course, recompiling with a different
compiler, version, or optimization level may cause a different register to
be used and complete garbage to be returned. UB at its best.

S
 
J

Jack Klein

Jack, thank you. Could please give some suggestion on the usage of
`assert()'.

I think, an runtime value makes assert() failed in debug version can
also (always) make it failed in release version, but in the release
version (NDEBUG defined) the `assert()' means null, so it can't catch
runtime error in release version.

C doesn't define "debug version" and "release version". If you want
the assert() macro to work, make sure that NDEBUG is not defined. If
you can't figure out how to modify your IDE's settings, ask in one of
Microsoft's support groups in the family on
their server msnews.microsoft.com.
 
L

lovecreatesbeauty

original question
//highdigit.h

#ifndef HIGH_DIGIT_H
#define HIGH_DIGIT_H

#define NUM_SYS 10 //

int HighDigit(int num);

#endif //HIGH_DIGIT_H

//highdigit.c

#include "highdigit.h"

int HighDigit(int num){
while (num >= NUM_SYS){
num /= NUM_SYS;
}

//return num; //omitted.
}


I test it on Linux & GCC again, and get the same problem as on Windows
& VC6.

If the argument `num' is larger than or equal to the Macro, the loop
body is executed and the result is right as if the `return num'
provided implicitly. But if the argument is less than the Macro, the
loop body is not executed. The result is undefinded.


Especially, when I use Jack's revised version (ignore the `return'
statement).

int HighDigit(int num, int base){
while (num >= base){
num /= base;
}

//return num; //omitted still
}

The result is always correct even if `num' is less than `base', and the
loop body is not executed also when `num' is less than `base'.


I don't konw `UB', `OP', `register' which Stephen Sprunk mentioned.
Could you please give me more help? Thank you.
 
K

Keith Thompson

lovecreatesbeauty said:
I test it on Linux & GCC again, and get the same problem as on Windows
& VC6.

If the argument `num' is larger than or equal to the Macro, the loop
body is executed and the result is right as if the `return num'
provided implicitly. But if the argument is less than the Macro, the
loop body is not executed. The result is undefinded.

The result is *always* undefined. The undefined result may, in some
cases, happen to be what you expect it to be. You should never depend
on this; the behavior can vary depending on anything, including the
phase of the moon or the importance of the customers watching your
demo.
 
K

Kevin D. Quitt

I test it on Linux & GCC again, and get the same problem as on Windows
& VC6.

It is working by accident. The compiler has (apparently) chosen to use
the same register for the calculation as it uses to return a value. This
is a pretty good strategy, and a common optimization. Change the code to
increment the value of a global variable and you'll likely get different
results.

I strongly suggest you turn up the warning level on your compiler - it
should be telling you about the error in your 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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top