|
jschell wrote:
void h(int* p) { return g(p); } Yuck. That's deceptive to me, as it makes it look like g(p) returns a value. I'd prefer writing it like this:
void h(int* p)
{
g(p);
return;
}
Software Zen: delete this;
|
|
|
|
|
Actually, if g(p) returns void, then this is definitely allowed. Makes generic programming easier, with less boilerplate, and faster compilation. Not sure what is supposed to happen if g(p) is something other than void - it should really be a syntax error.
|
|
|
|
|
Unsure, maybe, C back in the 80s. Or Pascal? But I always make sure each and every C function (or C# Method) has exactly one return statement. (I think I've written only one C# Method with more than one return, but that was an unusual situation.)
I agree that it "shows intent". Or potentially may help with debugging, though that's not usually critical either.
At the very least you know that it was written by a developer who has a long history of development, not one of these kids who is only interested in doing the absolute minimum and can't be trusted.
|
|
|
|
|
Quote: But I always make sure each and every C function (or C# Method) has exactly one return statement.
I followed the same for nearly 30 years.
Meanwhile I switched at least for 'void methods' to return imediatelly something does not fit. This to avoid 'nested if'
Still I'm fighting with that when a method needs to return a value. Here I stay with the pattern to have only _one_ return....
|
|
|
|
|
I believe it never was, as it was meant to be more or less compatible with C code, which doesn't require it.
Interestingly you can call main() from inside your C app, but not in C++.
Check out my IoT graphics library here:
https://honeythecodewitch.com/gfx
And my IoT UI/User Experience library here:
https://honeythecodewitch.com/uix
|
|
|
|
|
honey the codewitch wrote: Interestingly you can call main() from inside your C app, but not in C++. Really? I didn't know that.
I'll admit it's probably not a good idea, and there are easy ways around the prohibition, ... Hmm. I think I've figured some of it out.- There are multiple valid forms of
main(...) , and implementation-defined arguments are allowed. Allowing calls to it might require too much special case handling between the compiler and linker to ensure a match between the call and the actual implementation. - Another factor might be runtime initialization that takes place in
main() 's prolog. - Objects declared
static could potentially call main() before it had been called for the actual application startup. Sounds like the prohibition is a good way to make the compiler, linker, and runtime initialization job easier.
Software Zen: delete this;
|
|
|
|
|
Part of it might be static initialization behavior in C++ precludes it, but I don't know enough about the machinations of all that to be certain of anything.
Check out my IoT graphics library here:
https://honeythecodewitch.com/gfx
And my IoT UI/User Experience library here:
https://honeythecodewitch.com/uix
|
|
|
|
|
This piece of code
int main()
{
main();
} compiles fine. Anyway, I didn't try to run the executable.
"In testa che avete, Signor di Ceprano?"
-- Rigoletto
|
|
|
|
|
Hmm, well I've never actually tried it. I was relying on a lecture on C++.
I doubt it's standard though. I'm pretty sure dude knew what he was on about. He wasn't a nobody, but I forget his title.
Check out my IoT graphics library here:
https://honeythecodewitch.com/gfx
And my IoT UI/User Experience library here:
https://honeythecodewitch.com/uix
|
|
|
|
|
It looks 'the dude' was right. The C++ standard doesn't allow to call main recursively (and states that main 'shall not be used within a program').
Nevertheless, g++ allows that. You have to use -pedantic in order to get a warning.
"In testa che avete, Signor di Ceprano?"
-- Rigoletto
|
|
|
|
|
I don't remember his name and couldn't find the video at gunpoint so "the dude" abides.
Check out my IoT graphics library here:
https://honeythecodewitch.com/gfx
And my IoT UI/User Experience library here:
https://honeythecodewitch.com/uix
|
|
|
|
|
Agree. Such a requirement would break C compatibility.
"If we don't change direction, we'll end up where we're going"
|
|
|
|
|
honey the codewitch wrote: Interestingly you can call main() from inside your C app, but not in C++.
Odd.
Took me a bit to find a reference. Following seems to be best I could find.
Use the index to find '3.6' the click on page number. The first section there is the relevant one.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
"The function main shall not be used within a program. The linkage(3.5) of main is implementation-defined.
A program that defines main as deleted or that declares main to be inline, static, or constexpr is ill-formed. The name main is not otherwise reserved."
Although a draft I did find other mentions to this so I suspect is it substantially correct. Also other references suggest the updated spec matches (2014 to C14).
However I think the language of that is not as precise as some might think.
Since the linkage is not defined that means a compiler is free to do whatever it wants with it.
And the easiest way to handle that is to link it. Why? Because if it doesn't link it then it must figure out that the specific function is in fact the real entry point versus some other legitimate variation. Easier to just ignore the issue - which is allowed.
Also note that this restriction was added with newer versions of the spec. The original ANSI spec did not have any subsections in 3.6 at all.
-------------------------------------------------
Found the following also. See the second reply.
https://stackoverflow.com/questions/2128321/can-main-function-call-itself-in-c[^]
I didn't verify that one but the response suggests that the compiler is not responsible for telling you that you should not be calling main.
That is another one of things that as a compiler writer should not worry about. There are other things they should spend their time on to get right.
|
|
|
|
|
I hate the specs. They read like bad stereo instructions.
Check out my IoT graphics library here:
https://honeythecodewitch.com/gfx
And my IoT UI/User Experience library here:
https://honeythecodewitch.com/uix
|
|
|
|
|
To be fair though they do provide exactness. Especially the C and C++ ones. I know the Java one has numerous simple documented errors which have remained in place in all versions.
|
|
|
|
|
I doubt the language ever required it, but maybe some “lint” programs had that as a setting?
“Ensure there is at least one return statement for every function”
It would help catch the undefined return value if you forgot the return statement.
I could see a first generation lint program complaining of a missing return on a void function.
|
|
|
|
|
Maybe it's tag that has meaning only to the "creator". Mine are leftovers from extending a function then changing my mind.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Sorry I was under the impression that
int fn(){
int a;
return(0);
} was K&R, the cooler
void fn
{
int a;
} I though one the rules was 'thou shalt return a value!'
Glenn
|
|
|
|
|
In the C89 standard draft (the actual standard you have to buy).
Shows that return has never been required....minimalist approach...
https://port70.net/%7Ensz/c/c89/c89-draft.html#3.2.2.2
3.6.6.4 The return statement
...
Reaching the } that terminates a function is equivalent to executing a return statement without an expression.
|
|
|
|
|
mdblack98 wrote: Reaching the } that terminates a function is equivalent to executing a return statement without an expression.
My copy of the 1978 C reference manual contains the equivalent statement:
"Flowing off the end of a function is equivalent to a return with no returned value."
It also said that if 'return;' form is used, the returned value is undefined. The absence of a type declarator was assumed to mean 'int'. At that time there was no 'void' keyword. So, no need to search earlier than 1978 for the complete answer.
|
|
|
|
|
One of my first surprises (in the 90's) going from C++ to C, was that void was never used to define the return value of a main function. C++ had, at that point, always meant to be a superset of C and so had many odd things you wouldn't see in C for years (like variable declarations anywhere in the function).
My understanding was that C was always supposed to return a value to the operating system as an integer, regardless of what you did. So when C++ introduced void as a return type, even for main, I guess it was up in the air what you did in the end (that book has since been lost to a basement flooding so I can't remember or look up how it recommended to end the main function)
|
|
|
|
|
Juan Pablo Reyes Altamirano wrote: So when C++ introduced void as a return type, even for main
That statement is some what confusing as phrased.
Presumably originally C++ allowed for no return value from main(). Thus for compilation to succeed the type would need to be void.
That was because C allowed main to exit without a return value also.
The original C recommended a return value. And so does C++. Following is from "The C++ Programming Language Special Edition" section 6.1.5
"Conventionally, main() should return zero if the program terminates normally and nonzero otherwise."
And from 3.2
"If no value is returned, the system receive a value indicating successful completion"
So it is saying that the program doesn't need to but then a default value will be returned. So it is implicit.
|
|
|
|
|
Sorry to burst your bubble on dissing Pascal developers, but in Pascal you do not write void functions, it makes the sane distinction between functions (which return a value) and a procedure (which doesn't).
|
|
|
|
|
A long way (below) to get to the short version of the answer: No, it was never required and quite on purpose!! C was sort of ALGOL like and to get around one of the most common mechanical errors in assembly language, we forced ALGOL like structure. Some of those errors in assembler came from multiple entry and exit points from subroutines (what we call typed and untyped functions in C). Having an explicit "return" instruction even in an untyped function in C allowed for multiple exits from a function but only *one* entry. This fixed a lot of errors we used to get in assembly language. My opinion is that this is a semi-reasonable thing to do in C. When K&R wrote their initial "White Book" (mostly good for toilet paper!), they intentionally made the closing brace the equivalent of an explicit "return();" or "return;" statement. Remember that C was written to replace assembler on a PDP-8 or PDP-11 from Digital Equipment Corp. Such a machine might have used dual 186 kilobyte 8 inch single sided floppy disks and have maybe 16kB of main memory. To that end, a lot of things like implicit "return" and other things were implemented to save bytes on those floppy disks when the source files were saved. Same reason original C only allowed significance of 6 character function and variable names!!!
Too Long; Didn't Read Version:
I have been programming in "C" since BSD Unix and System III Unix first came to be available in the wild. Pretty sure early HPUX was a BSD release and where I did most work. Your question as posed cannot be answered because C and C++ are totally different languages and I would go so far as to say "C++" has *never* been a language! Stroustrop *never* got a standard for the initial C++ and standards such as C++17 (not sure I have the number right) look *nothing* like the C++ "things" I used when first using the prototype language versions. My point: C++17 is *NOT* C++ but a separate newer and incompatible language with numerous upgrades, stupid ideas, mistakes, and other differences from C++ as described by Stroustrop in his book. I think I gave my copy of the book to Half Price Books when we downsized our house. It was not uncommon for some of those languages to *require* and explicit return statement or even to require *just one* exit from a function. In some languages, an "untyped function" was instead called a "procedure". Just semantics... Now we have compilers with type checking and *many* other mechanical aids to make arguably correct code that we couldn't do in the 80s.
So, now that history lesson is over, I'll answer your question for C only from a 45 or so year perspective. The 1980's were a time when we in the business were struggling with ways to mechanically make sure our code was correct and error free. It spawned a *LOT* of languages designed for just that goal: Modula2, Pascal, Ada, PLM86, Pascal86, TurboPascal, PLM, etc. Most were based on ALGOL. A lot of those languages didn't ever make it to both microcomputers (remember when we had 65536 bytes of RAM and as much as 128k couldn't even be accessed) or to Unix. Much *real* code was being done in native assembly language, FORTRAN, or COBOL!!!! My ex-wife spent an entire 30 year career writing COBOL. DuPont ran entire chemical plants in the 80s on PDP-11s with 10s of thousands of lines written in FORTRAN.
In C (and to a small extent C++), the "return()" statement or the end brace, restores the previous stack pointers and then pops the address of the calling subroutine as part of executing the assembly language return from subroutine instruction. If you turn off optimization, the following code generates *2* rts instructions with one of those being dead code that can never be executed!
void test_program(void)
{
return;
}
test_program:
; set up the function stack as part of opening curly brace
push sp;
; return statement
pop sp;
rts;
; ending curly brace
pop sp;
rts;
; end of function
|
|
|
|
|
Early c-compilers could only return values but not expressions.
(this was a design flaw of the compiler/c language)
{
int x;
x = 42;
return x; return x + 1; return(x + 1);
This is why you see the return statement so often together with parentheses even when they aren't required anymore.
You should NOT write these unnesseccary parentheses anymore!
The return statement is not a function call; just omit the parentheses.
|
|
|
|