[comp.lang.c] prototype my function, please

ark@alice.UUCP (Andrew Koenig) (05/22/90)

In article <1231@wet.UUCP>, noah@wet.UUCP (Noah Spurrier) writes:

> I get the bad feeling that I am going to get flamed for this... But I can
> see no reason why my Turbo C compiler does not like the way I prototype
> the following program.

> /* Protoypte */
> void x (float);

	/* ... */

> void x (y)
> float y;
> {
>  printf ("%f",y);
> }

You should do it this way:

	void x(float y)
	{
		printf("%f",y);
	}

The point is that old-style parameter declarations are decidedly
not equivalent to new-style declarations.  For compatibility reasons,
it must be legal to define

	void x(y)
		float y;
	{
		/* ... */
	}

and call it from a separately compiled module without any declaration
there at all.  That means it must be capable of accepting a double
parameter.  Thus, in effect, this least example is equivalent to:

	void x(double dummy)
	{
		float y = dummy;
		/* ... */
	}

In other words, if you want to use ANSI-style function prototypes,
you must use them consistently.
-- 
				--Andrew Koenig
				  ark@europa.att.com

mercer@ncrstp.StPaul.NCR.COM (Dan Mercer) (05/25/90)

In article <1231@wet.UUCP> noah@wet.UUCP (Noah Spurrier) writes:
:
:
:I get the bad feeling that I am going to get flamed for this... But I can
:see no reason why my Turbo C compiler does not like the way I prototype
:the following program.
:
:#include <stdio.h>
:
:/* Prototype */
:void x (float);
:
:void main ()
:{
: x ((float)1);
:}
:
:void x (y)
:float y;
:{
: printf ("%f",y);
:}
:
:I keep getting a type mismatch error in function x() parameter float y;
:If I delete the prototype line the program works fine, but with warnings.
:
:Also just to make sure I was seeing straight I tried this nearly identical
:program. 
:
:#include <stdio.h>
:
:/* Protoypte */
:void x (int);
:
:void main ()
:{
: x (1);
:}
:
:void x (y)
:int y;
:{
: printf ("%d",y);
:}
:
:This works just fine, no warnings, no errors. Maybe I can't see the forest for
:the trees, so I am hoping someone else can take a chain-saw to this one...
:Oh if had only paid attention that day in class when they explain EXACTLY why
:I can't do what I am trying to do.
:
:I hope anyone can help...
:
:yours,
:
:Noah Spurrier
:noah@WET.UUCP


Maybe try the following:

/* Prototype */
void x (float);

void main ()
{
 x ((float)1);
}

void x (float y)   <========    change to ANSI declaration style
{
 printf ("%f",y);
}

My Turbo C has a fit if I mix  ANSI declarations with old style
declarations (makes porting code a real bitch)
-- 

Dan Mercer
Reply-To: mercer@ncrstp.StPaul.NCR.COM (Dan Mercer)

throopw@sheol.UUCP (Wayne Throop) (05/29/90)

> I get the bad feeling that I am going to get flamed for this...
No, but my reply may revive a long-forgotten flame-war...

>  But I can see no reason why my Turbo C compiler does not like 
> the way I prototype the following program.
> [..paraphrasing..
> void x(float);
> void main(){x(1.0);}
> void x(v) float v; {}   ..]

Many people pointed out quite correctly that the forward declaration
of the function disagrees with its definition later, because in old-style
function definitions, float is promoted to double.  The simplest way to
fix it is to change the third line to something like

> void x(float v){}

However, nobody seems to have noticed the other type gaffe, namely

> void main(){...}

The function named "main" in C environments is not how, and has never been,
of type (void ()).  At the very least, it should be declared as returning
an (int), and best of all is to declare it completely, with argc and argv and
the whole nine yards.

Remember: there is a contract with that fragment of your C environment
that invokes the main routine (often called "crt0" for reasons unknown to me)
which says that the routine will return an integer value.  It is unwise
to lie to the compiler in this way.
--
Wayne Throop <backbone>!mcnc!rti!sheol!throopw or sheol!throopw@rti.rti.org

darcy@druid.uucp (D'Arcy J.M. Cain) (05/31/90)

In article <0705@sheol.UUCP> throopw@sheol.UUCP (Wayne Throop) writes:
>> I get the bad feeling that I am going to get flamed for this...
>No, but my reply may revive a long-forgotten flame-war...
>
Yes but what else is Usenet for? :-)

> [..]
>However, nobody seems to have noticed the other type gaffe, namely
>
>> void main(){...}
>
>The function named "main" in C environments is not how, and has never been,
>of type (void ()).  At the very least, it should be declared as returning
>an (int), and best of all is to declare it completely, with argc and argv and
>the whole nine yards.
>
>Remember: there is a contract with that fragment of your C environment
>that invokes the main routine (often called "crt0" for reasons unknown to me)
>which says that the routine will return an integer value.  It is unwise
>to lie to the compiler in this way.
But if you always use exit() to end your program, isn't it sort of lying
to tell C that you will return an int?  As I recall that previous "flame
war" The problem with declaring main to return void was that the function
startup sequence might be different for different or no returns.  I can't
recall if anyone actually came up with an ANSI C compiler that had this
property but I am sure it is rare at best.  I think that if any compiler
acts this way it should handle the special case of main somehow.  At the
very least it should internally prototype main.  The best way of handling
it would be to use whatever the programmer declares to check return types
but to set the function call as if it had been declared properly.

So can anyone summarize the ANSI compilers (or K&R1 compilers for that
matter) for which decalaring main to return void causes a problem?

-- 
D'Arcy J.M. Cain (darcy@druid)     |   Government:
D'Arcy Cain Consulting             |   Organized crime with an attitude
West Hill, Ontario, Canada         |
(416) 281-6094                     |

steve@taumet.COM (Stephen Clamage) (06/01/90)

In article <1990May31.135230.242@druid.uucp> darcy@druid.UUCP (D'Arcy J.M. Cain) writes:
>So can anyone summarize the ANSI compilers (or K&R1 compilers for that
>matter) for which decalaring main to return void causes a problem?

The ANSI standard says that in a hosted environment, a strictly
conforming program will define main as
	int main() { /* ... */ }
or
	int main(int argc, char *argv[]) { /* ... */ }
(The names argc and argv are not required by the standard, but you
have to call the args something if they are declared.)

A compiler may allow anything it wishes in addition, but programs
depending on other defintions being legal may not be portable.

As to "lying to the compiler" when you terminate via exit(), the
standard says:
	"A return from the initial call to the _main_ function function
	is equivalent to calling the _exit_ function with the value returned
	by the _main_ function as its argument."
So the compiler is not allowed to be upset when exit() does not return.

I don't see any value in making lists of which detailed extensions are
supported by which particular compilers.  Compilers often accept (and
reject) different extensions in different releases.  Such a list
becomes quickly unmanageable.  Write for maximum portability and isolate
unavoidable dependencies for easy fixing.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

darcy@druid.uucp (D'Arcy J.M. Cain) (06/02/90)

In article <236@taumet.COM> steve@taumet.UUCP (Stephen Clamage) writes:
>In article <1990May31.135230.242@druid.uucp> darcy@druid.UUCP (D'Arcy J.M. Cain) writes:
>>So can anyone summarize the ANSI compilers (or K&R1 compilers for that
>>matter) for which decalaring main to return void causes a problem?
>
>As to "lying to the compiler" when you terminate via exit(), the
>standard says:
>	"A return from the initial call to the _main_ function function
>	is equivalent to calling the _exit_ function with the value returned
>	by the _main_ function as its argument."
>So the compiler is not allowed to be upset when exit() does not return.
>
I wasn't worried about exit() not returning.  Rather the fact that there
is no need to return from main if exit() is used to leave a program.  In
the following program:

#include <stdio.h>
int main(int argc, char **argv)
{
	printf("%s has %d arguments\n", *argv, argc);
	exit(0);
}

The compiler will give a warning that a function (main) which should
return an int does not return anything.  If, like me, you prefer super
quiet compiles you must add a return(0) statement.  You now have added
code (which won't be optimised out) which has no other purpose than to
shut the compiler up.  I will do that when necessary but try to avoid it
whenever possible.

Note that I realize that the exit above can be replaced by a return but
this is a trivial example.  In practice the exit may not even be in the
main routine.

-- 
D'Arcy J.M. Cain (darcy@druid)     |   Government:
D'Arcy Cain Consulting             |   Organized crime with an attitude
West Hill, Ontario, Canada         |
(416) 281-6094                     |

steve@taumet.COM (Stephen Clamage) (06/04/90)

In article <1990Jun2.091606.9125@druid.uucp> darcy@druid.UUCP (D'Arcy J.M. Cain) writes:
> ...
>#include <stdio.h>
>int main(int argc, char **argv)
>{
>	printf("%s has %d arguments\n", *argv, argc);
>	exit(0);
>}
>
>The compiler will give a warning that a function (main) which should
>return an int does not return anything. ...
>You now have added code (which won't be optimised out) which has no other
>purpose than to shut the compiler up. ...

Are you really concerned about one return statement in one function in
the entire program taking up code space but never being executed?

Do you ever include error-checking code in your programs to catch
"impossible" conditions?  You expect such code never to be executed,
and it surely uses more code space than "return 0;" at the end of main().

>In practice the exit may not even be in the main routine.

But what happens if *that* exit doesn't get executed (presumably due
to an error), and the program *does* return to main?  You should in
that case return some error value rather than 0 anyway, so you find out
about the incorrect return.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

karl@haddock.ima.isc.com (Karl Heuer) (06/05/90)

In article <239@taumet.COM> steve@taumet.UUCP (Stephen Clamage) writes:
>In article <1990Jun2.091606.9125@druid.uucp> darcy@druid.UUCP (D'Arcy J.M. Cain) writes:
>>int main(int argc, char **argv) { ... exit(0); }
>>[complains about int-valued function that seems to return void.  But if you
>>add a `return 0',] you now have added code (which won't be optimised
>>out) which has no other purpose than to shut the compiler up. ...
>
>Are you really concerned about one return statement in one function in
>the entire program taking up code space but never being executed?

On the implementation that I normally use, exit() is known to be a dead
function.  Hence, adding a `return' statement would *create* a warning about
unreachable code.

Besides which, you can't just write `exit(0); return 0;'.  You also have to
include a comment that says why you're doing something so silly, lest the next
person to read the code think you did it out of ignorance.

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint

steve@taumet.com (Stephen Clamage) (06/05/90)

In article <16790@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>On the implementation that I normally use, exit() is known to be a dead
>function.  Hence, adding a `return' statement would *create* a warning about
>unreachable code.

It seems some compilers complain about return, and some about absence of
return.  What to do?  What to do?

>Besides which, you can't just write `exit(0); return 0;'.  You also have to
>include a comment that says why you're doing something so silly, lest the next
>person to read the code think you did it out of ignorance.

True enough.  You can add a return following the exit, risking warnings
from the compiler, or omit it, risking warnings from the compiler.  In
this particular case, it would seem more sensible to omit the return,
since the ANSI standard says that exit cannot return to its caller.
With non-ANSI compilers, I have no preference.

My major point, however, was the hypothetical program by the orginal poster
which is intended to exit from some nested function and never get back to
main().  If we for the moment assume this is good programming practice,
I claim you still want a "return x;" at the end of main(), with a comment
saying this is an error return.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

e89hse@rigel.efd.lth.se (06/06/90)

In article <239@taumet.COM>, steve@taumet.COM (Stephen Clamage) writes:
>In article <1990Jun2.091606.9125@druid.uucp> darcy@druid.UUCP (D'Arcy J.M. Cain) writes:
>> ...
>>#include <stdio.h>
>>int main(int argc, char **argv)
>>{
>>	printf("%s has %d arguments\n", *argv, argc);
>>	exit(0);
>>}
>>
>>The compiler will give a warning that a function (main) which should
>>return an int does not return anything. ...
>>You now have added code (which won't be optimised out) which has no other
>>purpose than to shut the compiler up. ...
>
>Are you really concerned about one return statement in one function in
>the entire program taking up code space but never being executed?

 But that is ugly. In most unix versions of lint at least you 
 can put: /*NOTREACHED*/ after exit() to mark that the program never get to
that point.

karl@haddock.ima.isc.com (Karl Heuer) (06/11/90)

In article <246@taumet.com> steve@taumet.UUCP (Stephen Clamage) writes:
>[Given `int main(void) { ... exit(0); }'] It seems some compilers [would
>complain if a `return' were added], and some about absence of return [on an
>int function].  What to do?  What to do?

My opinion: leave it out, and if the compiler doesn't provide a way to
suppress the warning, then complain to the vendor.  Since it is very common to
leave main() with exit(), and since this is a defensible programming style,
the compiler should allow it--even if it has to make main() a special case.

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint

cknight@polyslo.CalPoly.EDU (King Claudius) (06/11/90)

karl@haddock.ima.isc.com (Karl Heuer) writes:
?steve@taumet.UUCP (Stephen Clamage) writes:
?>[Given `int main(void) { ... exit(0); }'] It seems some compilers [would
?>complain if a `return' were added], and some about absence of return [on an
?>int function].  What to do?  What to do?
?
?My opinion: leave it out, and if the compiler doesn't provide a way to
?suppress the warning, then complain to the vendor.  Since it is very common to
?leave main() with exit(), and since this is a defensible programming style,
?the compiler should allow it--even if it has to make main() a special case.

An easier way to do this is to declare main as returning void...

void main (void) {...}

-- 
cknight@polyslo.calpoly.edu                    ---King Claudius---

thorinn@skinfaxe.diku.dk (Lars Henrik Mathiesen) (06/11/90)

cknight@polyslo.CalPoly.EDU (King Claudius) writes:
>An easier way to do this is to declare main as returning void...

>void main (void) {...}

Yeah, and if a int-declared main expects a space to be left on the
stack for its return value, and a void-declared doesn't? Funny
core-dump time. The main function has a defined interface to the
runtime system, and you deviate from it at your peril. It may not
matter in _this_ release of _your_ compiler on _your_ operating
system, but ...

--
Lars Mathiesen, DIKU, U of Copenhagen, Denmark      [uunet!]mcsun!diku!thorinn
Institute of Datalogy -- we're scientists, not engineers.      thorinn@diku.dk

mcdaniel@amara.uucp (Tim McDaniel) (06/11/90)

cknight@polyslo.CalPoly.EDU (King Claudius) suggests:
   An easier way to do this is to declare main as returning void...

No, you can't.

To repeat what was just said a few weeks ago: the ANSI C standard says
that main may be defined in one of two ways, in a non-standalone-
program environment:
	int main(void) { /* ... */ }
or	int main(int argc, char *argv[]) { /* ... */ }
(Or, presumably, equivalent formulations.)  Section 2.1.2.2.1.
--
"I'm not a nerd -- I'm 'socially challenged'."

Tim McDaniel
Internet: mcdaniel@adi.com             UUCP: {uunet,sharkey}!puffer!mcdaniel

karl@haddock.ima.isc.com (Karl Heuer) (06/11/90)

In article <1990Jun11.123122.13249@diku.dk> thorinn@skinfaxe.diku.dk (Lars Henrik Mathiesen) writes:
>cknight@polyslo.CalPoly.EDU (King Claudius) writes:
>>An easier way to do this is to declare main as returning void...
>
>[But that could blow up if the function-call interface is different for void
>functions.]

Also, this practice may provoke a diagnostic from the compiler if it has
builtin knowledge of the correct prototype(s) for main().  (I find this
scenario more likely than the previous, especially in view of the common
missing-semicolon-before-main bug described in the FAQ.)

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint

darcy@druid.uucp (D'Arcy J.M. Cain) (06/12/90)

In article <2672bfbb.6b94@petunia.CalPoly.EDU> cknight@polyslo.CalPoly.EDU
(King Claudius) writes:
>karl@haddock.ima.isc.com (Karl Heuer) writes:
>?My opinion: leave it out, and if the compiler doesn't provide a way to
>?suppress the warning, then complain to the vendor.  Since it is very common to
>?leave main() with exit(), and since this is a defensible programming style,
>?the compiler should allow it--even if it has to make main() a special case.
>An easier way to do this is to declare main as returning void...
>
Bringing us back to last week's discussion of declaring main as void.  I think
Karl had the right idea.  No matter how elegant it is to think of it otherwise
main is not the same as other functions and a few special rules (in a hosted
environment) are not unreasonable.

-- 
D'Arcy J.M. Cain (darcy@druid)     |   Government:
D'Arcy Cain Consulting             |   Organized crime with an attitude
West Hill, Ontario, Canada         |
(416) 281-6094                     |