[comp.lang.c] Function Declarations

bobmon@iuvax.cs.indiana.edu (RAMontante) (08/20/88)

Craig Dawson asks about a program in which two routines try to call a
third, somewhat as follows:

x() { static z(); z(); }
y() { static z(); z(); }

static z() { ; }

(MSC apparently chokes; BTW, TurboC accepts it.)  My question is... Why
declare z() inside the functions x() and y()?  It doesn't make sense
that the name "z" should be localized to these code blocks, since it
has to be global to the entire file (at least) anyway.  Nor do I see
the value of making it a static name, since it references an object
that can't go away or be "reclaimed" outside of x() or y(), namely a
function.  Craig's "fix", declaring static z() prior to and outside of
both x() and y() (an almost-protoype kind of declaration), seems like
the only natural thing to do.

Note:  I understand why local variables are good.  But it seems pointless
to treat the function name as "local", since it must refer to a nonlocal
object.  What am I missing?  Is there a relevant section of K&R I should
read?
-- 
--    bob,mon			(bobmon@iuvax.cs.indiana.edu)
--    "Aristotle was not Belgian..."	- Wanda

chris@mimsy.UUCP (Chris Torek) (08/21/88)

In article <11879@iuvax.cs.indiana.edu> bobmon@iuvax.cs.indiana.edu
(RAMontante) writes:
>... somewhat as follows:
>x() { static z(); z(); }
>y() { static z(); z(); }
>static z() { ; }
>
>(MSC apparently chokes; BTW, TurboC accepts it.)  My question is... Why
>declare z() inside the functions x() and y()? ... declaring static z()
>prior to and outside of both x() and y() ... seems like the only natural
>thing to do.

Why do some people like a certain 181-novel 1930s and 1940s SF pulp
series?  The only answer is `style':  Some people just do.  (Incidentally,
with the publication of `In Hell, Madonna' as `The Red Spider', now there
are 182.)

(Now I wonder how many people will recognise the series named above...)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

jfh@rpp386.UUCP (The Beach Bum) (08/22/88)

In article <11879@iuvax.cs.indiana.edu> bobmon@iuvax.UUCP (RAMontante) writes:
>Craig Dawson asks about a program in which two routines try to call a
>third, somewhat as follows:
>
>x() { static z(); z(); }
>y() { static z(); z(); }
>
>static z() { ; }
>
>(MSC apparently chokes; BTW, TurboC accepts it.)  My question is... Why
>declare z() inside the functions x() and y()?  It doesn't make sense
>that the name "z" should be localized to these code blocks, since it
>has to be global to the entire file (at least) anyway.  Nor do I see
>the value of making it a static name, since it references an object
>that can't go away or be "reclaimed" outside of x() or y(), namely a
>function.  Craig's "fix", declaring static z() prior to and outside of
>both x() and y() (an almost-protoype kind of declaration), seems like
>the only natural thing to do.

the msc compiler is broken.  the code should compile without error
as written (more or less ...)

as for the Rational behind why this is being done, ask the programmer.
the minimalist coding would be

static z();

x() { z(); }
y() { z(); }
static z() { ; }

a possible rationality behind his coding in the fashion he did is
that the functions were actually much larger than what we have above
and he wanted to indicate that the functions x() and y() were both
dependent on z().  as for why z() is declared to be static, any
number of reasons exist.
-- 
John F. Haugh II                 +--------- Cute Chocolate Quote ---------
HASA, "S" Division               | "USENET should not be confused with
UUCP:   killer!rpp386!jfh        |  something that matters, like CHOCOLATE"
DOMAIN: jfh@rpp386.uucp          |         -- apologizes to Dennis O'Connor

suitti@haddock.ima.isc.com (Steve Uitti) (08/22/88)

In article <5680@rpp386.UUCP> jfh@rpp386.UUCP (The Beach Bum) writes:
>In article <11879@iuvax.cs.indiana.edu> bobmon@iuvax.UUCP (RAMontante) writes:
>>Craig Dawson asks about a program in which two routines try to call a
>>third, somewhat as follows:
>>
>>x() { static z(); z(); }
>>y() { static z(); z(); }
>>
>>static z() { ; }
>>
>>(MSC apparently chokes; BTW, TurboC accepts it.)  My question is... Why
>>declare z() inside the functions x() and y()?

	Supporting other peoples code is more difficult than
supporting your own.  A thirty file program where everything (that can
be) is declared static is much easier to support than one that
doesn't.  "ctags", "grep", and cxref only do so much for you.
	The tighter the scope of each variable and function, the
better.  I generally try to declare the functions before all uses:
static z(a) int a; { ; }
static y() { z(5); }
static x() { y(); z(); }
main() { x(); }
	Kind of reminds you of Pascal (except that you can tell where
"main" starts).  The complexity of a program at any point seems to be
tied exponentialy to the number of variables and functions available
to it at that point.
	Unfortunately, the compilers that I've used that support
prototypes don't "automatically generate" them using this style.  If I
want prototypes for the above, I need:
static z(a) int a; { ; }
#ifdef PROTOTYPES_SUPPORTED
static z(int a); /* prototype for z() */
#endif /* PROTOTYPES_SUPPORTED */
static y() { z(5); }
static x() { y(); z(); }
main() { x(); }
	Which is too bad, since it really has all the info it could
possibly want, and I'll probably just screw up the prototype (since I can).

	On PDP-11's, the linker (ld) can run out of symbol space for
the symbol table if you don't do this.  Generally, the larger editors
that have been ported to this machine got hundreds of routines
declared "static", just to allow compilation.  This wasn't "bad".  It
made the products easier to maintain.

	Another favorite is this:
y() { z(); }
static z() { ; }
	This often yields something like "redeclaration of z".  The
first reference defaults to something like "extern int z();" for a
declaration.  I've always thought that this was a language feature.
It encourages better behaviour without requiring it.  Of course the
following is fine:
static z() { ; }
y() { z(); }

	Stephen

scjones@sdrc.UUCP (Larry Jones) (08/23/88)

In article <5680@rpp386.UUCP>, jfh@rpp386.UUCP (The Beach Bum) writes:
> In article <11879@iuvax.cs.indiana.edu> bobmon@iuvax.UUCP (RAMontante) writes:
> >Craig Dawson asks about a program in which two routines try to call a
> >third, somewhat as follows:
> >
> >x() { static z(); z(); }
> >y() { static z(); z(); }
> >
> >static z() { ; }
> >
> >(MSC apparently chokes; BTW, TurboC accepts it.) 
> 
> the msc compiler is broken.  the code should compile without error
> as written (more or less ...)

NO!!!  Amazingly enough, MSC got this right - the code is wrong.  Think about
this similar code:
  x() { static z[]; z[0] = 3; }
  y() { static z[]; z[0] = 5; }

  static z[10];
You wouldn't expect that to work, would you?  If something is declared within
a block, it must be defined within the same block unless it is declared extern.
Since you can't define functions within a block, you can't declare a static
function within a block.  Sorry.

----
Larry Jones                         UUCP: uunet!sdrc!scjones
SDRC                                      scjones@sdrc
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150                  AT&T: (513) 576-2070
Nancy Reagan on superconductivity: "Just say mho."

markro@microsoft.UUCP (Mark Roberts) (08/25/88)

In article <356@sdrc.UUCP> scjones@sdrc.UUCP (Larry Jones) writes:
>NO!!!  Amazingly enough, MSC got this right - the code is wrong.

Thanks for the answer; here is (I believe) the appropriate section from the
May 88 draft standard (3.5.1, pg 56, lines 19-20):

  "The declaration of an identifier for a function that has block scope
   shall have no explicit storage-class specifier other than extern."

[ Amazingly? (:-) ]

haugj@pigs.UUCP (Joe Bob Willie) (08/25/88)

In article <1757@microsoft.UUCP> microsof!markro writes:
>In article <356@sdrc.UUCP> scjones@sdrc.UUCP (Larry Jones) writes:
>>NO!!!  Amazingly enough, MSC got this right - the code is wrong.
>
>Thanks for the answer; here is (I believe) the appropriate section from the
>May 88 draft standard (3.5.1, pg 56, lines 19-20):
>
>  "The declaration of an identifier for a function that has block scope
>   shall have no explicit storage-class specifier other than extern."

is it too late to get this changed back in the standard?  this seems to
be a serious mis-feature.  i have used function declarations inside
of functions to document where a function is used.  now they are telling
us we can't document static functions in this fashion.

i know this has been discussed before, but what exactly is The Committee
trying to do to C?  this one change will result in virtually all of the
code i've written being broken.  [ along with much code i've not written
but still have to maintain ]  the resulting language will share only the
name with the original language.
-- 
 jfh@rpp386.uucp	(The Beach Bum at The Big "D" Home for Wayward Hackers)

                              "ANSI C: Just say no"
                                                -- Me.

bill@proxftl.UUCP (T. William Wells) (08/26/88)

A random point on prototypes: we have the need to include
prototypes in our code while still being able to compile the code
with compilers that did not support prototypes.

The solution is this: first, all function arguments are of a type
for which the argument widening action is null.  (ints are OK,
short is not.) Second, we have, in a global include file,
something like this:

	/* Configuration section */

	#define ANSI_PROTO      /* This line would be added if the
				   compiler has prototypes.  Note that
				   just using __STDC__ is not sufficient,
				   as there are many compilers that have
				   prototypes but do not define it.  */

	/* This stuff is buried somewhere deep in the include file, the
	   person compiling our code does not look at it. */

	#ifdef ANSI_PROTO
	#define FUNC(n,p) n p;
	#else
	#define FUNC(n,p) n ();
	#endif

This is the code that makes use of the prototype macro.

	#include <our_file.h>

	FUNC(int function, (int arg1, int arg2))

What happens is that, in the default file we ship, ANSI_PROTO is
not specified and the FUNC macro will expand into something like

	extern int function();

And, since we use the right argument types, this will work on
non-ANSI or ANSI compilers.  If, however, the user *does* define
ANSI_PROTO, the FUNC macro expands to

	extern int function(int arg1, int arg2));

and he gets the type checking benefits of the prototype.


---
Bill
novavax!proxftl!bill

bill@proxftl.UUCP (T. William Wells) (08/27/88)

In article <371@pigs.UUCP> haugj@pigs.UUCP (Joe Bob Willie) writes:
: >  "The declaration of an identifier for a function that has block scope
: >   shall have no explicit storage-class specifier other than extern."
:
: is it too late to get this changed back in the standard?  this seems to
: be a serious mis-feature.  i have used function declarations inside
: of functions to document where a function is used.  now they are telling
: us we can't document static functions in this fashion.

Yes.  I made a complaint about the change in the linkage rules,
but they made it clear (for "reasons" explained in the Rationale)
that they were not going to fix it.

I have come to the conclusion that the only proper way to use
functions in ANSI C is to place prototypes for all functions
defined or referenced in a source file either in included files
or at the top of the file.

This seems to be the only simple solution to the problem.  Argh.

: i know this has been discussed before, but what exactly is The Committee
: trying to do to C?

Standardize it.  Sometimes by forcing the language to be usable
on lowest-common-denominator class implementations.  This is the
*only* reason given for this brain-damage.  Since the Rationale
also asserts that "Existing code is important, existing
implementations are not." (p.2, section 1.1) I find their
rationalization to be sheer hypocrisy.

In general, the committee has done a good job, but I can't
(won't, actually, since I save those words for people with no
apparent redeeming characterics) express the depths of my disgust
or the degree of my condemnation for this moral failure on the
part of the committee.

:                     this one change will result in virtually all of the
: code i've written being broken.  [ along with much code i've not written
: but still have to maintain ]  the resulting language will share only the
: name with the original language.

I wouldn't go quite so far; I have had no problem adapting my
coding habits to be compatible with existing practice and with
the ANSI standard.

---
Bill
novavax!proxftl!bill

bill@proxftl.UUCP (T. William Wells) (08/29/88)

The message I sent had a minor error in it, here is the correction. Sorry.

In article <619@proxftl.UUCP> I wrote:
: This is the code that makes use of the prototype macro.
:
:       #include <our_file.h>
:
:       FUNC(int function, (int arg1, int arg2))

I should have written:

: This is the code that makes use of the prototype macro.
:
:       #include <our_file.h>
:
:       extern FUNC(int function, (int arg1, int arg2))

---
Bill
novavax!proxftl!bill

iiit-sh@cybaswan.UUCP (Steve Hosgood) (08/31/88)

In article <1757@microsoft.UUCP> microsof!markro writes:
>..... here is (I believe) the appropriate section from the
>May 88 draft standard (3.5.1, pg 56, lines 19-20):
>
>  "The declaration of an identifier for a function that has block scope
>   shall have no explicit storage-class specifier other than extern."
 
In article <371@pigs.UUCP> haugj@pigs.UUCP (Joe Bob Willie) writes:
>is it too late to get this changed back in the standard?  this seems to
>be a serious mis-feature.  i have used function declarations inside
>of functions to document where a function is used.  now they are telling
>us we can't document static functions in this fashion.
>
>i know this has been discussed before, but what exactly is The Committee
>trying to do to C?  this one change will result in virtually all of the
>code i've written being broken.  [ along with much code i've not written
>but still have to maintain ]  the resulting language will share only the
>name with the original language.

I agree, Joe Bob, I've got the same problem exactly! This had better get
to the the comp.std.c group *now* so they can discuss it before it *is*
too late.

I think the compiler is correct according to the standard, but the standard
is broken. However, the compiler *ought* to produce an error message. After
all, declaring a function static within a block would mean that it would
have to be *defined* within that block in order to be both visible and
usable. However, C has no mechanism for declaring functions within blocks,
so at very least the static declaration should cause an error message to that
effect.

Someone's pinched my K&R, but I'm sure it says that this is a special case
for the reasons I've mentioned above. ANSI have *got* to decide one way or
another, I hope they change lines 19-20, page 56!

I hope no-one objects, but I've directed follow-ups to comp.std.c
Even if ANSI are right, I think you'd agree that this is a standards problem
now, not just MSC.

-----------------------------------------------+------------------------------
Steve Hosgood BSc,                             | Phone (+44) 792 295213
Image Processing and Systems Engineer,         | Fax (+44) 792 295532
Institute for Industrial Information Techology,| Telex 48149
Innovation Centre, University of Wales, +------+ JANET: iiit-sh@uk.ac.swan.pyr
Swansea SA2 8PP                         | UUCP: ..!ukc!cybaswan.UUCP!iiit-sh
----------------------------------------+-------------------------------------
            My views are not necessarily those of my employers!

mouse@mcgill-vision.UUCP (der Mouse) (09/01/88)

In article <371@pigs.UUCP>, haugj@pigs.UUCP (Joe Bob Willie) writes:
> In article <1757@microsoft.UUCP> microsof!markro writes:
>> In article <356@sdrc.UUCP> scjones@sdrc.UUCP (Larry Jones) writes:
>>> NO!!!  Amazingly enough, MSC got this right - the code is wrong.
>> [F]rom the May 88 draft standard (3.5.1, pg 56, lines 19-20):
>>  "The declaration of an identifier for a function that has block
>>   scope shall have no explicit storage-class specifier other than
>>   extern."
> i have used function declarations inside of functions to document
> where a function is used.  now they are telling us we can't document
> static functions in this fashion.

Not at all; just that you can't mention that they're static in the
block.  I *would* be surprised to find that there's anything wrong with
something like

foo()
{
 ...
  { double glurf(char*,int);
    ...
  }
 ...
}

static double glurf(char *s,int maxlen)
{
 ...
}

You're confusing the two meanings of the static keyword.  When used
inside a function, `static' means one thing: the object being declared
has static storage class.  Here, `static' really is a storage class
specifier.  Outside a function, `static' means something else: the name
being declared is to be accessible only from within the file the
definition appears in.  Here, it's really a linkage specifier rather
than a storage class specifier.

In retrospect, I think it was probably a mistake to overload `static'
this way, but it is certainly far too late to change it now.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

chris@mimsy.UUCP (Chris Torek) (09/01/88)

In article <1275@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse)
writes:
>... I *would* be surprised to find that there's anything wrong with
>something like

[compressed vertically]

>foo() { ... { double glurf(char*,int); ... } }
>static double glurf(char *s,int maxlen) { ... }

Surprise!

According to the dpANS, the first declaration of a static function must
label that function as static.  Now we also know (from the discussion
chain in the references: line) that function declarations within other
functions may not be labelled `static'.  Putting these together, the
*only* legal ways to write this are:

	static double glurf(char *, int);
	foo() { ... /* call glurf */ ... }
	static double glurf(char *s, int maxlen) { ... }

or

	static double glurf(char *s, int maxlen) { ... }
	foo() { ... /* call glurf */ ... }
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

bill@proxftl.UUCP (T. William Wells) (09/03/88)

In article <13344@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
: Surprise!
:
: According to the dpANS, the first declaration of a static function must
: label that function as static.  Now we also know (from the discussion
: chain in the references: line) that function declarations within other
: functions may not be labelled `static'.  Putting these together, the
: *only* legal ways to write this are:
:
:       static double glurf(char *, int);
:       foo() { ... /* call glurf */ ... }
:       static double glurf(char *s, int maxlen) { ... }
:
: or
:
:       static double glurf(char *s, int maxlen) { ... }
:       foo() { ... /* call glurf */ ... }

Yes. Shriek! Scream! Shout! Curse! Puke! etc.................................

All in the name of easing a few implementers' lives.

Shame on you X3J11.

---

To change the subject slightly: a new hire was asking me if he
could use some macros to encapsulate some flag setting.

I told him no.

Why?

Because the only purpose of the macro was to decrease the number
of keystrokes *he* had to use.  But it would have made the next
reader of the code have to understand two different things, the
macro AND the flag, to understand the code, instead of one.

He asked me why.  I said: this code will be written once and read
many hundred times.  Whose job do you think ought to be made
easier: yours or that future reader (who may be yourself, several
times)?  He got the point.

How is this relevant, you might ask?

Well, consider the related question: who should have to deal with
the pain caused by systems that make one pass compilation
difficult: every user of ANSI C, or those people charged with the
writing of a C compiler for those systems?

It seems that the committee forgot this.

For shame!

(And yes, even though I think the committee has done a generally
good job, I will take every opportunity to condemn them for this
egregious lapse.)

---
Bill
novavax!proxftl!bill

haugj@pigs.UUCP (The Beach Bum) (09/05/88)

In article <697@proxftl.UUCP> bill@proxftl.UUCP (T. William Wells) writes:
>Well, consider the related question: who should have to deal with
>the pain caused by systems that make one pass compilation
>difficult: every user of ANSI C, or those people charged with the
>writing of a C compiler for those systems?

is this the claimed rational?  declaring functions as static local
to a referencing function _can_ be handled with single pass compilation.
the compiler may be easier to write than with that feature included,
but with it included, the compiler could still be single pass.
-- 
=-=-=-=-=-=-=-The Beach Bum at The Big "D" Home for Wayward Hackers-=-=-=-=-=-=
               Very Long Address: John.F.Haugh@rpp386.dallas.tx.us
                         Very Short Address: jfh@rpp386
                           "ANSI C: Just say no" -- Me

mouse@mcgill-vision.UUCP (der Mouse) (09/11/88)

In article <13344@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> In article <1275@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
>> I *would* be surprised to find that [this doesn't work]
>> foo() { ... { double glurf(char*,int); ... } }
>> static double glurf(char *s,int maxlen) { ... }
> Surprise!

You have such a lovely way of phrasing things, Chris... :-)

> Putting these together, the *only* legal ways to write this are:

> 	static double glurf(char *, int);
> 	foo() { ... /* call glurf */ ... }
> 	static double glurf(char *s, int maxlen) { ... }
> or
> 	static double glurf(char *s, int maxlen) { ... }
> 	foo() { ... /* call glurf */ ... }

Since the whole idea was to document the fact that foo calls glurf,
near the point of call (ie, in foo), how about:

	static double glurf(char *, int);
	foo() { double glurf(char *, int); ... /* call glurf */ ... }
	static double glurf(char *s, int maxlen) { ... }

Is this permitted?

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

swh@hpsmtc1.HP.COM (Steve Harrold) (12/07/88)

Re: Function prototypes

The MSC /Zg switch is useful, but doesn't do everything.  For example,

1) All parameters that are structs or pointer to structs get translated to
   "struct UNNAMED".  If you then use these function prototypes in your code,
   you will get compile-time messages announcing a type mismatch between the
   the non-existent "struct UNNAMED" and whatever struct is actually in your
   code.  For MSC, this is a warning, and the compilation succeeds.  For
   Turbo C, this is an error, and compilation fails.  For older (non-ANSI)
   compilers, there is no message.

2) If you use <varargs.h> in your parameter list, the function prototype that
   is generated names a type "va_alist", rather than inserting the "..." string
   that ANSI uses to denote optional (varargs) parameters.  Again, the
   compiler complains about the mismatch (usually "too many parameters").

Still, it's better than nothing.
--
---------------------
Steve Harrold			...hplabs!hpsmtc1!swh
				HPG200/13
				(408) 447-5580
---------------------

cramer@optilink.UUCP (Clayton Cramer) (12/10/88)

In article <11480014@hpsmtc1.HP.COM., swh@hpsmtc1.HP.COM (Steve Harrold) writes:
. Re: Function prototypes
. 
. The MSC /Zg switch is useful, but doesn't do everything.  For example,
. 
. 1) All parameters that are structs or pointer to structs get translated to
.    "struct UNNAMED".  If you then use these function prototypes in your code,
.    you will get compile-time messages announcing a type mismatch between the
.    the non-existent "struct UNNAMED" and whatever struct is actually in your
.    code.  For MSC, this is a warning, and the compilation succeeds.  For
.    Turbo C, this is an error, and compilation fails.  For older (non-ANSI)
.    compilers, there is no message.

Easy solution: always create a structure tag when you do a typedef.  I'm
amazed how many people don't realize that struct and enum optionally
accept a tag.  Use the tag, and the /Zg switch will produce useful
prototypes.

. 2) If you use <varargs.h. in your parameter list, the function prototype that
.    is generated names a type "va_alist", rather than inserting the "..." string
.    that ANSI uses to denote optional (varargs) parameters.  Again, the
.    compiler complains about the mismatch (usually "too many parameters").

ANSI C uses stdarg.h, not varargs.h.  Use stdarg.h in Microsoft C, and
the /Zg switch will produce ... in a form that is useful.

. Steve Harrold			...hplabs!hpsmtc1!swh

-- 
Clayton E. Cramer
{pixar,tekbspa}!optilin!cramer          (Note new path!)

john_gibney%830.312@fidogate.fido.oz (John Gibney) (09/06/89)

Original to: all

I am trying to work out what the following decalration means:- 
 
    int (*function)() = NULL; 
 
 

and it is later used:- 
 
    (*function)(); 
 
 

I would appreciate it if anyone could explain this code to me. 
I am fairly new to C and I think this code may help me 
with a menu program I am currently writing. 
 
 

Thanks. 
 

John  :-) 
 
 

---
 * Origin: Southern Mail CBCS - An OZNET System (Opus 7:830/312)