[comp.lang.c] Subroutine layout in C

phil@uxg.cso.uiuc.edu (12/21/88)

I want to write a subroutine in C, called S.  I want S to be known outside.
I also want to have two subroutines X and Y to be known ONLY to S (not known
outside of S).  Either can be called by S, and each calls the other in a
recursive way.  I also need to share several variables entirely within
this context (shared between S, X, Y).  They can be static.  There will
only be 1 instance of S (and therefore also of X and Y, but that should
be hidden).  Main program M should be able to call S, but any references
to X and Y will not be resolved by the module S.

How do I lay out the arrangement of source for S?  An example would be
appreciated.  Thanks.

--Phil--

burgett@adobe.com (Michael Burgett) (12/22/88)

In article <2800002@uxg.cso.uiuc.edu> phil@uxg.cso.uiuc.edu writes:
[ description of needed module deleted ]
>How do I lay out the arrangement of source for S?  An example would be
>appreciated.  Thanks.

in a file, say S.c:

static int foo, bar;	/* foo and bar are accessable by all functions
			   in this file but are not visible outside it. */

int S()			/* S() will be available as a public symbol */
{
  ...
}

static int f1()		/* can be referenced by S() or f2() but is not
{			   visible outside this file			*/
  ...
}

static int f2()		/* can be referenced by S() or f1() but is not
{			   visible outside this file			*/
  ...
}


should do what you are asking for...
		----------------------------------
			mike burgett
		     burgett@adobe.com
	   "squid and red bean stew served daily...."

gpasq@picuxa.UUCP (Greg Pasquariello X1190) (12/22/88)

In article <2800002@uxg.cso.uiuc.edu> phil@uxg.cso.uiuc.edu writes:
-
-I want to write a subroutine in C, called S.  I want S to be known outside.
-I also want to have two subroutines X and Y to be known ONLY to S (not known
-outside of S).  Either can be called by S, and each calls the other in a
-recursive way.  I also need to share several variables entirely within
-this context (shared between S, X, Y).  They can be static.  There will
-only be 1 instance of S (and therefore also of X and Y, but that should
-be hidden).  Main program M should be able to call S, but any references
-to X and Y will not be resolved by the module S.
-
-How do I lay out the arrangement of source for S?  An example would be
-appreciated.  Thanks.
-
---Phil--

Here's how to do it.  This is in the source file S.c, and assumes that the
routines return ints.  Just change your code accordingly if they don't.  It
also does not show any function parameters, so you will have to customize
your code for that also (obviously).

/*
	This declares your functions and variables as static (i.e. known 
	only within this source module).  See K+R2 A4.1.
*/
static int X();
static int Y();

static int var1;
static int var2;

/*
	This declaration of S() will enable it to be found externally when
	called by any other routine in the program, for example M().  Notice
	that S has access to the both the static variables and the static
	functions X() and Y().
*/
S() 
	{
	var1 = 1;
	X();
	Y();
	...
	}

/*
	Here, your two static functions X() and Y() have access to the 
	variables, as well as each other.
*/
static int X()
	{
	var1 = var2 = 0;
	Y();
	...
	}

static int Y()
	{
	var1 = var2 = 0;
	X();
	...
	}


-- 
=============================================================================
By the time they had diminished from 		  Greg Pasquariello AT&T PMTC
50 to 8, the dwarves began to suspect Hungry.	  att!picuxa!gpasq  
=============================================================================

evil@arcturus.UUCP (Wade Guthrie) (12/23/88)

In article <2800002@uxg.cso.uiuc.edu>, phil@uxg.cso.uiuc.edu writes:
 
> I want to write a subroutine in C, called S.  I want S to be known outside.
> I also want to have two subroutines X and Y to be known ONLY to S (not known
> outside of S).  Either can be called by S, and each calls the other in a
> recursive way.  I also need to share several variables entirely within
> this context (shared between S, X, Y).  They can be static.  There will
> only be 1 instance of S (and therefore also of X and Y, but that should
> be hidden).  Main program M should be able to call S, but any references
> to X and Y will not be resolved by the module S.
> 

In a file, which is separately compiled before being linked to the rest
of your code, put S(), X(), and Y().  Declare X() and Y() to be static
which, in addition to causing variables to maintain their values between
calls, causes symbols to be unknown outside that file.  As an example:

----- file foo.c -------------
#include <stdio.h>

main()
{
	global();
	local();
}

----- file bar.c -------------
#include <stdio.h>

int
global()
{
	puts("entered global");
	local();
	puts("leaving global");
}

static int
local() { puts("  calling local"); }
--------------------------

try compiling it, and you'll see that main cannot access local.  It works
if you either 1) remove the call to local in main, or 2) remove the static
declaration of local.


Wade Guthrie
Rockwell International
Anaheim, CA

(Rockwell doesn't necessarily believe / stand by what I'm saying; how could
they when *I* don't even know what I'm talking about???)

frank@rsoft.UUCP (Frank I. Reiter) (12/23/88)

In article <2800002@uxg.cso.uiuc.edu> phil@uxg.cso.uiuc.edu writes:
>
> I want S to be known outside.
>I also want to have two subroutines X and Y to be known ONLY to S (not known
>outside of S).  Either can be called by S, and each calls the other in a
>recursive way.  I also need to share several variables entirely within
>this context (shared between S, X, Y).  They can be static.

Put S(), X(), and Y() in their own file.  Declare X() and Y() to be static
and do the same with any global variables to be accessed only by S(), X(),
and Y().

Other modules will be able to call S() but not X() or Y() or any of the static
variables.

-- 
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
Frank I. Reiter             \ /    UUCP:    {uunet,ubc-cs}!van-bc!rsoft!frank
Langley, British Columbia   / \     BBS:    Mind Link @ (604)533-2312
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*

eric@snark.UUCP (Eric S. Raymond) (12/23/88)

In article <2800002@uxg.cso.uiuc.edu>, phil@uxg.cso.uiuc.edu writes:
> I want to write a subroutine in C, called S.  I want S to be known outside.
> I also want to have two subroutines X and Y to be known ONLY to S (not known
> outside of S).  Either can be called by S, and each calls the other in a
> recursive way.  I also need to share several variables entirely within
> this context (shared between S, X, Y).  They can be static.  There will
> only be 1 instance of S (and therefore also of X and Y, but that should
> be hidden).  Main program M should be able to call S, but any references
> to X and Y will not be resolved by the module S.
> 
> How do I lay out the arrangement of source for S?  An example would be
> appreciated.  Thanks.

Let xreturn, yreturn and sreturn be the return types of X, Y and S. Then the
simplest way to accomplish this is:

static int sharevar1;
static char *sharevar2;

static xreturn X()
{
     yreturn Y();	/* this is the trick; forward-declare Y() */

    /* text of X */
}

static yreturn Y()
{
    /* text of Y */
}

sreturn S()
{
    /* text of S */
}

You might want to put S() up front and forward-declare X() and Y(). That would
look like:

sreturn S()
{
     xreturn X();
     yreturn Y();

    /* text of S */
}

I use a #define forward /*empty*/ so I can write:

sreturn S()
{
     forward xreturn X();
     forward yreturn Y();

    /* text of S */
}

Be aware that there is some theological variation among C compilers on whether
forwards in functions remain in effect for only function scope until the end of
the module file. ANSI C, I believe, assumes the former, and writing as if the
former were true does no harm on compilers that assume the latter.

I gather you're a novice. Congratulations on having learned concern for scope
and visibility issues early. Too many people never break the bad habit C
encourages of leaving their functions and data promiscuously exposed.
-- 
      Eric S. Raymond                     (the mad mastermind of TMN-Netnews)
      Email: eric@snark.uu.net                       CompuServe: [72037,2306]
      Post: 22 S. Warren Avenue, Malvern, PA 19355      Phone: (215)-296-5718

djones@megatest.UUCP (Dave Jones) (12/28/88)

From article <eWZhv#4VSvya=eric@snark.UUCP>, by eric@snark.UUCP (Eric S. Raymond):

> 
> I use a #define forward /*empty*/ so I can write:
> 


I am starting a definitive (ahem) collection of SLMs. This has the
distinction of being the first.

eric@snark.UUCP (Eric S. Raymond) (12/29/88)

In <1130@goofy.megatest.uucp>, djones@megatest.UUCP (Dave Jones) writes:
> I am starting a definitive (ahem) collection of SLMs. This has the
> distinction of being the first.

SLM = Silly Little Macro? :-) Here're two more that I use:

#define	const	/*empty*/	/* on non-ANSI compilers */
#define public	/*empty*/

This latter goes with

#define private static

I may drop `forward' though.
-- 
      Eric S. Raymond                     (the mad mastermind of TMN-Netnews)
      Email: eric@snark.uu.net                       CompuServe: [72037,2306]
      Post: 22 S. Warren Avenue, Malvern, PA 19355      Phone: (215)-296-5718

dmg@ssc-vax.UUCP (David Geary) (01/06/89)

Frank Reiter writes:
>In article <2800002@uxg.cso.uiuc.edu> phil@uxg.cso.uiuc.edu writes:
>>
>> I want S to be known outside.
>>I also want to have two subroutines X and Y to be known ONLY to S (not known
>>outside of S).  Either can be called by S, and each calls the other in a
>>recursive way.  I also need to share several variables entirely within
>>this context (shared between S, X, Y).  They can be static.

>Put S(), X(), and Y() in their own file.  Declare X() and Y() to be static
>and do the same with any global variables to be accessed only by S(), X(),
>and Y().

>Other modules will be able to call S() but not X() or Y() or any of the static
>variables.

  Frank is correct, this is exactly what you want to do.  However, I like
to do the following:

#define PRIVATE static
#define PUBLIC 

Now, we can declare the functions S(), X(), and Y() thusly:

PUBLIC int S()
{
 ...
}

PRIVATE int X()
{
 ...
}

PRIVATE int Y()
{
 ...
}

And, of course, we can declare external variables in the same manner:

PUBLIC  int   x,y;
PRIVATE float f,g;

BTW, these macros are not my invention, I first saw them in a book entitled
"Operating Systems Design and Implementation" (I think the title is correct).
A very good book BTW, on the MINIX OS.

David


-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ David Geary, Boeing Aerospace,               ~ 
~ #define    Seattle     RAIN                  ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ariel@lznh.UUCP (<10000>Ariel Aloni) (01/06/89)

In article <2459@ssc-vax.UUCP> dmg@ssc-vax.UUCP (David Geary) writes:
>
>  Frank is correct, this is exactly what you want to do.  However, I like
>to do the following:
>
>#define PRIVATE static
>#define PUBLIC 
> ...
Sure, this thing has no end, why not :

#define TINY short
#define HUGE long
#define RECORD struct
..... :-)

C is terse and accurate, if you want to invent new keywords for C
please don't abuse CPP, design your own new language.
In your particular example the change of 'static' is very confusing
since 'static' has a different meaning for functions and variables.

ariel

-- 
Ariel A. Aloni                                 att!lznh!ariel

bowles@eris.berkeley.edu (Jeff A. Bowles) (01/07/89)

>In article <2459@ssc-vax.UUCP> dmg@ssc-vax.UUCP (David Geary) writes:
>
>  Frank is correct, this is exactly what you want to do.  However, I like
>to do the following:
>
>#define PRIVATE static
>#define PUBLIC 
> ...

I worked for a very short time for a creepy compiler company that had
several hundred thousand lines of this sort of crap.

	PRIVATE  -> static
	PUBLIC	-> ""
	INT16	-> short int
	INT32	-> long int

and so on. By the time these fools were done, they weren't coding
in C, they were coding in their own language - and often it was just
because they liked a particular style that the K&R compiler [proper]
didn't accept.

One person I know used typedef's for every last data type in a fairly
large control system. You would see a declaration like
	THING x;
and not know if you could put "&" in front of it (it might be an array)
or if it was a integral object or what. Data hiding is one thing, but
not if it's incomplete, and not if it serves no purpose.

We've all seen (or heard about) the source to the Bourne shell, in which
Steve Bourne furnished ALGOL-like #defines and wrote the entire shell in
it. (Don't get me wrong, I like Algol W, an older language, more than I
do C - in many contexts.)

But if you're using the C preprocessor, or things like typedefs, to
reformat a program, ask how much you're asking someone to know about
your program before you do it. It's one thing to clarify an often-existing
sequence of code, e.g.
	#define	REGLOOP(i)	for(i = 0; i < REGSZ; ++i)
or to hide an implementation within library routines or header files,
as in the case of the "-ldbm" or "-lmp" libraries, and another to gratituously
add the sort of foolishness the original posting suggests.

Some people use:
	typedef enum {true = 1, false = 0} boolean;
and when you're able to use this single line, and later say "if (true)..."
I'll probably use this - it DOES make things clearer. I believe that ANSI C
will make this sort of thing easier, which is good.


Where is the line? Probably the best way to answer is by asking if the
statement (e.g. "if (true)..." or "REGLOOP(i) { ... }") would make sense
in a fragment.

And it's hard to convince me that most pretty-printing would.

	Jeff Bowles

mlandau@bbn.com (Matt Landau) (01/07/89)

In comp.lang.c (<1987@lznh.UUCP>), ariel@lznh.UUCP (<10000>Ariel Aloni) writes:
>>#define PRIVATE static
>>#define PUBLIC 
>C is terse and accurate, if you want to invent new keywords for C
>please don't abuse CPP, design your own new language.

In general, this is good advice.  If you're going to program in C, then
program in *C*; don't end up with something like the original /bin/sh
code, which no real C programmer ends up wanting to deal with.  But . . .

>In your particular example the change of 'static' is very confusing
>since 'static' has a different meaning for functions and variables.

. . . on the other hand, this is precisely why an alias for "static"
may be a *good* idea.  

One can argue that overloading static with two different meanings was 
a flaw in the original language design -- there does not seem to me to 
be all that much similarity between persistent variables in a function 
and variables/functions that are hidden from other source files, so it's
not clear why you would want to use the same keyword to describe both.

Using something like PRIVATE for file-level static variables or functions, 
and the traditional static for variables that persist across function
invocations, serves to make the distinction clear.
--
 Matt Landau			Waiting for a flash of enlightenment
 mlandau@bbn.com			  in all this blood and thunder

nagel@blanche.ics.uci.edu (Mark Nagel) (01/07/89)

In article <1987@lznh.UUCP>, ariel@lznh (<10000>Ariel Aloni) writes:
|In article <2459@ssc-vax.UUCP> dmg@ssc-vax.UUCP (David Geary) writes:
|>
|>  Frank is correct, this is exactly what you want to do.  However, I like
|>to do the following:
|>
|>#define PRIVATE static
|>#define PUBLIC 
|
|C is terse and accurate, if you want to invent new keywords for C
|please don't abuse CPP, design your own new language.
|In your particular example the change of 'static' is very confusing
|since 'static' has a different meaning for functions and variables.

Wrong, it makes it more clear.  The static keyword is overloaded, so
why is it confusing to rename it to more accurately reflect the
desired semantics?  It is easy to abuse cpp, but this is not such a
case.

Mark Nagel @ UC Irvine, Dept of Info and Comp Sci
ARPA: nagel@ics.uci.edu              | The world is coming to an end.
UUCP: {sdcsvax,ucbvax}!ucivax!nagel  | Please log off.

djones@megatest.UUCP (Dave Jones) (01/07/89)

From article <1987@lznh.UUCP), by ariel@lznh.UUCP (<10000)Ariel Aloni):
) In article <2459@ssc-vax.UUCP) dmg@ssc-vax.UUCP (David Geary) writes:
))
))  Frank is correct, this is exactly what you want to do.  However, I like
))to do the following:
))
))#define PRIVATE static
))#define PUBLIC 
)) ...
) Sure, this thing has no end, why not :
) 
) #define TINY short
) #define HUGE long
) #define RECORD struct
) ..... :-)
) 

Point of order.

Would it be acceptable for me to install these last three
in my SLM database, even though they are conspicously smileyed?

I missed the last USNIX Symposium on Ethics in Net.sarcasm.

djones@megatest.UUCP (Dave Jones) (01/07/89)

From article <18789@agate.BERKELEY.EDU>, by bowles@eris.berkeley.edu (Jeff A. Bowles):

> Some people use:
> 	typedef enum {true = 1, false = 0} boolean;
> and when you're able to use this single line, and later say "if (true)..."
> I'll probably use this - it DOES make things clearer.

I can't agree. I know of one _extremely_ large project where several
programmers have defined "YES" and "NO" and "TRUE" and "FLASE".
So you get "redefined" messages if you need to include header
files from two different packages.  To make things worse,
one programmer who was unfamiliar with C conventions defined
"YES" as 0 and "NO" as 1.  Gack.  His header files will break
all the other ones.  That sort of proves that an SLM was out of place:
It has to mean what it means. If you change the #define, you change
the logic and break the program.

I've noticed that some released Sun software gets "redefined" messages.
In one header file there is something like this:

    #define true (0==0)

and in another

    #define true (0!=1)

or something like that.

Pooh.

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/07/89)

In article <2459@ssc-vax.UUCP> dmg@ssc-vax.UUCP (David Geary) writes:
>#define PRIVATE static
>PRIVATE int X() { ... }

The only legitimate reason for doing this is to make it convenient
to force these functions to have external linkage when using a
debugger that doesn't provide decent support for static functions.

>#define PUBLIC 

This one is a waste of time.

evil@arcturus.UUCP (Wade Guthrie) (01/10/89)

In article <18789@agate.BERKELEY.EDU>, bowles@eris.berkeley.edu (Jeff A. Bowles) writes:
> I worked for a very short time for a creepy compiler company that had
> several hundred thousand lines of this sort of crap.
> 
> 	PRIVATE  -> static
> 	PUBLIC	-> ""
> 	INT16	-> short int
> 	INT32	-> long int

In general I agree that typedefs and macros should be used judiciously
in order to help make things readable to the ordinary C programmer (if
you can call *any* C programmer ordinary :-> ).  However, I have seen
the use for INT16 and INT32 -- portability where the precision is
absolutely important.

For example: you want to partition a circle into little angles, and you
want to flag an occurrence of something if it exists in each angle.  The
way I chose to implement this was to partition my circle into 32 sections
(the number of bytes in the long or int on my machine -- to take advantage
of the speed improvements on some operations, I chose to use int) and do 
bitwise operations to set and check flags represented by the bits in 
that int.  Now, I need to port this to a machine that has 16 bit ints --
portability falls on its face.  This can be circumvented by using INT32 
where the size is important (and using short, int, and long where it is
not so critical).
 

Wade Guthrie
evil@arcturus.UUCP
Rockwell International
Anaheim, CA

(Rockwell doesn't necessarily believe / stand by what I'm saying; how could
they when *I* don't even know what I'm talking about???)