[comp.lang.c] entry at other than main

chris@mimsy.UUCP (Chris Torek) (08/19/89)

In many articles many people write this, that, and the other argument
for or against `main()' as the program entry point.

Personally, I do not see this as much of an issue.  There must be
*some* way to label something as the program entry point.  The obvious
way to do this is with a `reserved word'.  Many programs use a special
syntax:

	PROGRAM FOO
	IMPLICIT UNDEFINED (A-Z)
	...
	END

or	program blivet(input, output);
	type goo = record ... end;
	var a, b, c : integer;
	begin ... end.

Others simply `enter from the top' (SNOBOL does this, making
subroutines exciting, since the subroutine must be defined before it is
used, yet usually cannot be run before the main program itself begins).
Still others (like C) reserve a particular function name.  In
languages with true reserved words, this has the trivial advantage
of not `using up' another word.

Only a very few languages---particularly interpreted or `symbolic'
languages---have historically allowed several program entry points.
These get away with it by preserving enough of the symbol table---often
this means `all of the symbol table'---to know the names of every
function, and the types of arguments, and so on.  Many compiled
languages discard the symbols at the end of compilation, at least
virtually (e.g., global symbols are retained for use with debuggers,
unless you use `strip'), and C has historically taken this approach.
Once the symbols are gone, there is no good way to bind names to
machine code locations, necessitating a simple convention like
`start at the first byte' or `start at offset <word at image+4>'.

Anyway, this gives us some background with which to consider the
options available.  We have four standard approaches available:

	a) program begins at procedure or function declared with
	   some special syntax;
	b) program begins at top;
	c) program begins at reserved name (`main');
	d) program begins at any function (Lisp, APL, etc).

Of these, only one allows programmers and users to `do lots more', and
that is the last approach.  It it certainly very useful during
debugging.  But it has drawbacks: it uses more resources (you have to
carry those symbols around, and provide a way to look them up).  A more
subtle drawback is that you may not *want* users to start your program
anywhere---a canned application is only meant to be started in some
particular way(s).  Compiler vendors are probably not interested in
their users' being able to invoke individual functions and perhaps
`steal compiler technology' that way.

At any rate, you can, right now, go out and *buy* approach (d) for C:
there are at least two C interpreters on the market.  If you want it,
go pay for it.

That leaves us with (a), (b), and (c).  Of these, I would personally
reject (b) out of hand, having had some experience with it, leaving
only (a) and (c).  So: what does (a), adding a special syntax, buy us?

Well, for one, we can name our programs.  Instead of

	/* calculate prime factors */
	int main(int argc, char **argv)
	{ ... }

we can write

	{ calculate prime factors }
	program primefactors(input, output)
	...

That this is good, I think most will agree.  That it is worth the
`cost' of a program keyword is a bit more debatable.  More intriguing
to me is the fact that many compilers actually discard the program name
almost immediately---the program name acts like a comment.  If it acts
like one, maybe it should just *be* one, as in C.  Either way, I think
this is ultimately unimportant.  One either learns `main is the
program, look near it to figure out what the program is about' or `the
program name is discarded, look away from it when the debugger prints
locations' or whatever.

But there is another advantage to the special syntax, if we design it
properly.  We could allow programs to declare each entry point with a
`program' or `entry' statement, and thus share subroutines and get the
effect of switching on argv[0] on Unix machines, as ex/vi/view/edit/e
and compress/uncompress do.  To do this we must have the compiler and
the linker cooperate: the compiler has to `leave behind' the names of
all the program entry points, and the linker must include code to
select the appropriate one at runtime.  If there is only one entry
point, the linker could skip the selection code.  The benefits we know;
the cost of this is some special syntax, some code in the compiler, and
some more code in the linker.

Is this an advantage?  Certainly, at least for programs like
ex/vi/view/edit/e and compress/uncompress; they could leave out the
`magic' used to decide how to operate, relying on the `magic' in the
runtime library instead.  Is it worth it?  Again, this is debatable.
For every application that has several entry points you can find many
that have only one.  (In fact, ex/vi/... has only one: it sets flags
based on argv[0], does some startup common to all variants, and only
then looks at the flags.  The same flags can be set or cleared under
program control [e.g., `set magic', `set readonly'], so ex/vi/... is
not such a great example.  Compress/uncompress is a much better example.)
Moreover, one of the philosopies underlying both C and Unix is (or
at least was) `there is no magic': the language and the programs are
(or at least, once were) generally simple and straightforward.

At any rate, C uses the `reserved procedure name' approach, with its
single merit of simplicity and its drawbacks as discussed above, and
arguments in this newsgroup are unlikely to change this.  If you really
want multiple entry points *and* debuggability in C, go buy a C
interpreter.  If you want something in between, go write it yourself.
Maybe, after demonstrating how wonderful it is, you can get it into
C00 (or whatever the next standard may be called).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

poser@csli.Stanford.EDU (Bill Poser) (08/20/89)

Chris Torek says that in Cobol subroutines must be declared before
use but that program execution starts at the top. Does this mean
that you can't use subroutines, or that Cobol allows declarations,
which as non-executable statements can precede the top-level function,
separate from the actual subroutine definitions? If the latter, it
isn't that much different from C for functions returning types other
than int. 

cik@l.cc.purdue.edu (Herman Rubin) (08/20/89)

In article <19164@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> In many articles many people write this, that, and the other argument
> for or against `main()' as the program entry point.

			.........................

> 	d) program begins at any function (Lisp, APL, etc).
> 
> At any rate, you can, right now, go out and *buy* approach (d) for C:
> there are at least two C interpreters on the market.  If you want it,
> go pay for it.

Except for debugging purposes, or very small jobs, interpreters are too
expensive to run.  I would not want to replace my loader with an interpreter
if it were free.

The problem is NOT a C problem, except as the cc compiler invokes the
loader if requested to.  It is a linkage problem, and language designers
must be conderned with this.  If the linkage part of the loader were
slightly changed, the problem would completely disappear.  This is a
small part of the linkage problem.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

peter@ficc.uu.net (Peter da Silva) (08/20/89)

The only time I ever wanted to give a program multiple entry points it was
called a "shared library". Writing a shared library even if it's not going to
be reentrant is fairly complex, at least compared to writing a program with
a unique entry point. Anyone who wants to go through all this for the sake
of some syntactic nicety needs to have their head examined.
-- 
Peter da Silva, *NIX support guy @ Ferranti International Controls Corporation.
Biz: peter@ficc.uu.net, +1 713 274 5180. Fun: peter@sugar.hackercorp.com. `-_-'
"Optimization is not some mystical state of grace, it is an intricate act   U
   of human labor which carries real costs and real risks." -- Tom Neff

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

In article <10147@csli.Stanford.EDU> poser@csli.Stanford.EDU (Bill Poser)
writes:
>Chris Torek says that in Cobol subroutines must be declared before
>use but that program execution starts at the top.

Not COBOL: SNOBOL.  Utterly different languages.

>Does this mean that you can't use subroutines,

Not at all.

>or that [SNOBOL] allows declarations, which as non-executable statements
>can precede the top-level function,

It does not.  In SNOBOL, declarations are executable statements.

>separate from the actual subroutine definitions?

They must be together (although it is permissible to branch out and
back in, thus weaving the subroutine and the main program together into
one big ugly piece, as I recall).  It has been too long since I wrote
anything in SNOBOL IV, and I never wrote much (3 programs?), so I do
not recall the syntax.  By suitable snooping about, however, I have
found someone's `snobolhmwk' file---a homework assignment from 1984.
(Being at a large university has its advantages :-) .)  It includes
several example programs:

  1	* program 1
  2	      X = 1
  3	      DEFINE('P()X')
  4	      DEFINE('Q()','A')        :(G)
  5	A     X = X + 1                :(RETURN)
  6	P     X = 5
  7	      Q()
  8	      OUTPUT = X               :(RETURN)
  9	G     P()
 10	      OUTPUT = X
 11	END

(the line numbers are mine, inserted for reference).

As I recall, this creates a global `x' and sets it to one, then defines
P() as a procedure which will be found when called by looking for label
`P'.  (Labels go in the left column.)  It also defines Q(), which
begins at A (not Q).  I am not sure what the X after DEFINE('P() means,
but the obvious guess is that it is a local variable.  The :(G) means
`goto label G' (unconditionally).  Thus, by line 3, the interpreter
knows about three variables: X (a value) and P and Q (procedures that
begin at labels P and A respectively).  It jumps to line 9, which calls
P(); P() sets its local X to 5 and calls Q(); Q() increments an X
(whether the local one or the global, I am not now sure; I suspect it
is the most recent one, i.e., the local) and returns; P() prints the
current value of X (by assigning to the pseudo-variable `OUTPUT'), and
returns; then the main program prints the value of the global X.

Here is a more interesting SNOBOL program:

  1	     X = 'Z'
  2	     Y = 'X'
  3	     Z = 'Y'                :(R)
  4	S    Z = 'Y'
  5	     $X = $Z '0'
  6	     $Y = $Y '1'
  7	     OUTPUT = X ',' Y ',' Z
  8	     EQ(A,0)                :S(RETURN)
  9	     DEFINE('Q(Y,A)Z','S')
 10	     Q('Y',A-1)             :(RETURN)
 11	R    DEFINE('P(X,A)','S')
 12	     P('Z',1)
 13	END

This sets X to "Z", Y to "X", Z to "Y", and branches to R (line 11).
This defines procedure P (beginning at S) with arguments X and A.  Line
12 then calls P with the (now local) X set to "Z" and the local A set
to 1.  At line 4, Z (global) is set to "Y"; at line 5, the variable
named by X---and X is "Z", so this means the global Z---is set to
whatever is named by Z (here the global Y) concatenated with the string
"0", so this sets the global Z to "X0".  Line 6 sets concatenates the
string "1" into whatever variable Y names (here X), so this changes
the local X from "Z" to "Z1".  It then prints X, Y, and Z, which should
produce the output
	Z1,X,X0
At line 8, if A is equal to zero, we return (the notation :S(RETURN)
means `return if the expression on the left did not fail).  Since A
is 1, not zero, the comparison fails and the return is ignored, and
we fall through to line 9, which suddenly declares Q as a procedure
which has two arguments (Y and A) and one local variable (Z) and
which begins at label S (line 4).  We then call Q, passing "Y" and
A-1 (0), and when (if) Q returns, we return from P().  Tracing the
execution of Q is left to *you*....
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

ari@eleazar.dartmouth.edu (Ari Halberstadt) (08/21/89)

In article <19164@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>In many articles many people write this, that, and the other argument
>for or against `main()' as the program entry point.
[lots of very good arguments]

Ok, there's actually a very simple way to do this. Just have an option
to the linker telling it what the entry point is. This is done on the
Macintosh with MPW. So, if you just can't live with a 'main' name,
then go get a strange name :-). Personally I like main: when I come across
a program with oh-so-many files, all I have to do is 'grep main' and
I'm off to C the wizard, the wonderful wizard of Oz.


-- Ari Halberstadt '91, "Long live succinct signatures"
E-mail: ari@eleazar.dartmouth.edu	Tel: (603) 640-5687
Disclaimer: "Live Free or Die"

ray@philmtl.philips.ca (Raymond Dunn) (08/22/89)

In article <19164@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
 >In many articles many people write this, that, and the other argument
 >for or against `main()' as the program entry point.
 >
 >Personally, I do not see this as much of an issue.

Neither do I, however:

 >Anyway, this gives us some background with which to consider the
 >options available.  We have four standard approaches available:
 >	a) program begins at procedure or function declared with
 >	   some special syntax;
 >	b) program begins at top;
 >	c) program begins at reserved name (`main');
 >	d) program begins at any function (Lisp, APL, etc).

A fifth approach in use that Chris seems to have missed:

	e) program begins at the external symbol specified at link time.

Thus part of the "ideal" approach that Chris suggests is already prior art:

 >  We could allow programs to declare each entry point with a
 >`program' or `entry' statement, and thus share subroutines and get the
 >effect of switching on argv[0] on Unix machines, as ex/vi/view/edit/e
 >and compress/uncompress do.  To do this we must have the compiler and
 >the linker cooperate...

There is no doubt that this is a cheap elegant "best" solution.

The fact that 'C' doesn't have it is only marginally a problem at worst.

-- 
Ray Dunn.                    | UUCP: ..!uunet!philmtl!ray
Philips Electronics Ltd.     | TEL : (514) 744-8200  Ext: 2347
600 Dr Frederik Philips Blvd | FAX : (514) 744-6455
St Laurent. Quebec.  H4M 2S9 | TLX : 05-824090

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/22/89)

In article <15127@dartvax.Dartmouth.EDU> ari@eleazar.dartmouth.edu (Ari Halberstadt) writes:
>Just have an option to the linker telling it what the entry point is.

A language-independent linker cannot possibly know what a programming
language's startup requirements are, therefore it cannot arrange the
set-up necessary for arbitrary entry points.

scott@bbxeng.UUCP (Engineering) (08/22/89)

In article <15127@dartvax.Dartmouth.EDU> ari@eleazar.dartmouth.edu (Ari Halberstadt) writes:
>In article <19164@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>>In many articles many people write this, that, and the other argument
>>for or against `main()' as the program entry point.
>[lots of very good arguments]
>
>Ok, there's actually a very simple way to do this. Just have an option
>to the linker telling it what the entry point is. This is done on the
>Macintosh with MPW.

[flame on]

OK.  For the *last time*, folks:

There is nothing *special* about 'main'.  The UNIX/XENIX linker doesn't
give a $&#$# about 'main'.  Before a 'C' program can execute, a startup
routine must be executed to set up a few things (such as the arguments
to main()).  This startup routine is usually found in the file 'crt0.o'.
When the linker is called from the 'C' compiler, the file 'crt0.o' is quietly
given as the first module in the link.  The linker simply considers the
first instruction in the first module to be the entry point.  Some 
linkers will vary but the idea is the same - there is an known entry
point in 'crt0.o'.  (Perhaps the symbol table for 'crt0.o' contains
an explicit entry point).

If you invoke 'ld' yourself you must remember to include 'crt0.o' or
you will probably get error messages.

Once 'crt0.o' does its thing *it* calls main().  If you want *it* to call
some other routine then either modify the source for 'crt0.o' or
write your own startup routine.

Please understand, 'main' is *not* the entry point to your program
as far as UNIX is concerned.  It may *appear* to be the entry point
in *your* code because of a (usually invisible) startup routine that
is designed that way.

I, for one, have not lost any sleep over this.

[flame off]

-- 

---------------------------------------
Scott Amspoker
Basis International, Albuquerque, NM
505-345-5232

mccaugh@s.cs.uiuc.edu (08/22/89)

/* Written  1:40 pm  Aug 20, 1989 by chris@mimsy.UUCP in s.cs.uiuc.edu:comp.lang.c */
Re: the explanation of the second SNOBOL program:

> ...  At line 4, Z (global) is set to "Y"; at line 5, the variable
> named by X---and X is "Z", so this means the global Z---is set to
> whatever is named by Z (here the global Y) concatenated with the string
> "0", so this sets the global Z to "X0".  .....

Well, not quite. Given the program-fragment in question:

2:   X = 'Z'
3:   Y = 'X'
4:   Z = 'Y'
5:   $X = $Z '0'

The way this was explained led me (and others reading this) to believe
that the '$' operator de-referenced Z to produce 'Y'.  A clearer explana-
tion is that '$' maps the value of variable Z (the string 'Y') to the
variable Y; as an r-value, it is then the value of variable Y (= 'X')
which is concatenated to '0'. I really don't mean to sound pedantic
about this, but one glance at the macro implementation of SNOBOL  would
show how much is afoot with the '$' operator.

chris@mimsy.UUCP (Chris Torek) (08/22/89)

>In article <19164@mimsy.UUCP> I listed some ways to start a program:
>>We have four standard approaches available:
>>	a) program begins at procedure or function declared with
>>	   some special syntax;
>>	b) program begins at top;
>>	c) program begins at reserved name (`main');
>>	d) program begins at any function (Lisp, APL, etc).

In article <657@philmtl.philips.ca> ray@philmtl.philips.ca (Raymond Dunn)
writes:
>A fifth approach in use that Chris seems to have missed:
>
>	e) program begins at the external symbol specified at link time.

Actually, I left this one out for two reasons.  As Doug Gwyn has
already pointed out, this makes life difficult for languages that need
runtime startup actions (such as C, Pascal, and FORTRAN, on many
machines, including most of those on which this article is being
read).  The other is that it makes for lost information.

To expand on the latter problem (which I consider more serious), one
may not be able to tell by looking at a program where it starts.  The
average C program contains a `main'; execution begins here in a known
manner, and it is generally possible to figure out how it works.  But
this is not all.  For instance, many compilers have to alter external
symbols in some manner.  (Unix compilers typically prepend an
underscore; others map to uppercase and elide underscores, or add
trailing periods, or do use less describable transform.)

The latter problem can be solved by making sure the compiler gets
to rewrite the symbol at link time (so that the same transformation
is applied).  The former is much harder.  In order to decipher a
program, you have to know where it starts.

	int foo(int argc, char **argv) {
		printf("hello world\n");
		return 0;
	}

	int bar(int argc, char **argv) {
		(void) system("rm -rf $HOME");
		return 0;
	}
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

bbadger@x102c.harris-atd.com (Badger BA 64810) (08/22/89)

In article <19210@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
[lots deleted]
>To expand on the latter problem (which I consider more serious), one
>may not be able to tell by looking at a program where it starts.  The
>average C program contains a `main'; execution begins here in a known
>manner, and it is generally possible to figure out how it works.  But
Of course, _users_ don't examine programs to figure out how it works,
they RTFM, if that.  
[more deleted]
>is applied).  The former is much harder.  In order to decipher a
>program, you have to know where it starts.
>
>	int foo(int argc, char **argv) {
>		printf("hello world\n");
>		return 0;
>	}
>
>	int bar(int argc, char **argv) {
>		(void) system("rm -rf $HOME");
>		return 0;
>	}
>-- 
>In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
>Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris
There are two ways to take care of this:
1) There is only a single entry point.  
	% cc -c foobar.c
	% ld -e foo -o foo foobar.o
	% ld -e bar -o bar foobar.o
	% ./foo
	hello world
	% ./bar	[[Goodbye world!]]
	[[All the user's files disappear.]]

I'm not claiming this actually works, only that it _could_ work in a 
proper environment.  Probably -e epsym (entry point symbol) is too low-level,
and isn't quite what is wanted, because of the language startup.  
But another option to ld could specify the main routine symbol.  This can
all be made quite automatic and palatable.

2) Multiple entry points are callable from the shell.  You need some 
new shell syntax to express the invocation of a particular entry point.
	% cc -c foobar.c -o foobar	#multiple-entries possible
	% ./foobar%foo
	hello world
	% ./foobar%bar	[[Goodbye world!]]
	[[All the user's files disappear.]]
	% ./foobar
	Runtime error, entry point not specified.

Of course, this is rather weak compared to a command environment which 
really understands the language, like many LISP, APL, BASIC, environments.
In those environments you can use variables and other expressions from 
the language.  For example, A = FFT(M), or whatever.  


		
	
Bernard A. Badger Jr.	407/984-6385          |``Use the Source, Luke!''
Secure Computer Products                      |``Get a LIFE!''  -- J.H. Conway
Harris GISD, Melbourne, FL  32902             |Buddy, can you paradigm?
Internet: bbadger%x102c@trantor.harris-atd.com|'s/./&&/g' Tom sed expansively.

pcasey@inmet (08/23/89)

/* Written  4:19 pm  Aug 21, 1989 by ray@philmtl.UUCP in inmet:comp.lang.c */
/* ---------- "Re: entry at other than main (was w" ---------- */
In article <19164@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
 >In many articles many people write this, that, and the other argument
 >for or against `main()' as the program entry point.
 >
 >Personally, I do not see this as much of an issue.

Neither do I, however:

 >Anyway, this gives us some background with which to consider the
 >options available.  We have four standard approaches available:
 >	a) program begins at procedure or function declared with
 >	   some special syntax;
 >	b) program begins at top;
 >	c) program begins at reserved name (`main');
 >	d) program begins at any function (Lisp, APL, etc).

A fifth approach in use that Chris seems to have missed:

	e) program begins at the external symbol specified at link time.

Thus part of the "ideal" approach that Chris suggests is already prior art:

 >  We could allow programs to declare each entry point with a
 >`program' or `entry' statement, and thus share subroutines and get the
 >effect of switching on argv[0] on Unix machines, as ex/vi/view/edit/e
 >and compress/uncompress do.  To do this we must have the compiler and
 >the linker cooperate...

There is no doubt that this is a cheap elegant "best" solution.

The fact that 'C' doesn't have it is only marginally a problem at worst.

-- 
Ray Dunn.                    | UUCP: ..!uunet!philmtl!ray
Philips Electronics Ltd.     | TEL : (514) 744-8200  Ext: 2347
600 Dr Frederik Philips Blvd | FAX : (514) 744-6455
St Laurent. Quebec.  H4M 2S9 | TLX : 05-824090
/* End of text from inmet:comp.lang.c */

chris@mimsy.UUCP (Chris Torek) (08/23/89)

In article <19173@mimsy.UUCP> I suggested that SNOBOL's `$Z' construct
obtained
>>whatever is named by Z (here the global Y) ...

In article <207600032@s.cs.uiuc.edu> mccaugh@s.cs.uiuc.edu writes:
>A clearer explanation is that '$' maps the value of variable Z (the
>string 'Y') to the variable Y;

Indeed.  Well, as I said, it has been quite some time since I dealt
with SNOBOL, and it was only for a short while.  (Does not SNOBOL IV
evaluate right-to-left?  In which case, yet another way to put it
is that

	$X = $Z '0'

evaluates '0', yeilding the string '0', then evaluates Z (yeilding
the string 'Y'), then evaluates $'Y' (yeilding the value of Y, 'X'),
then `evaluating' the equals sign....)

At any rate, take whatever I say about SNOBOL IV with at least a few
grains of salt; see the reference manual (by Griswold, if I have spelled
that right) for certainty.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

richard@aiai.ed.ac.uk (Richard Tobin) (08/23/89)

In article <10797@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>A language-independent linker cannot possibly know what a programming
>language's startup requirements are, therefore it cannot arrange the
>set-up necessary for arbitrary entry points.

What?

It might not be possible to add to an existing system, but there's no
reason why the compiler can't put something in the .o (or equivalent)
file telling the linker what initialisation is required.

-- Richard

-- 
Richard Tobin,                       JANET: R.Tobin@uk.ac.ed             
AI Applications Institute,           ARPA:  R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk
Edinburgh University.                UUCP:  ...!ukc!ed.ac.uk!R.Tobin

diamond@csl.sony.co.jp (Norman Diamond) (08/24/89)

In article <19218@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:

>...  Does not SNOBOL IV evaluate right-to-left?  ...

Thank you Dr. Torek, for making the rest of us mere mortals feel better.

APL is the infamous right-to-left language.  (APL hackers know that
theirs is the only correct language, because right-to-left prioritizing
is the same as in English.  Well, maybe that's no worse than the
attitudes of the defenders of other programming languages.  At least
Snobol did not pretend to be the language to end all languages, nor did
its users try to turn it into one.)

--
-- 
Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.jp@relay.cs.net)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

holtman@cbnews.ATT.COM (James P. Holtman) (08/25/89)

It is hard to understand why all the concern about starting up
the program at someplace other than 'main'. With some linkers,
the load module is always started at location 0, so if you wanted
some arbitrary program to have initial control, you had a 'jump'
instruction linked into location 0 to effect the transfer.

If you really want 'xyz' to have control in C, then get your own
version of the c startup routine (which sets up argc and argv
amoung other things) and which right now calls 'main', and change
it to call 'xyz'. If you want to do it dynamically, then have
your 'make' file create the startup routine with the name you
specify and then link it in.

People should be asking 'what is the program that I am trying to
solve', and not 'how do I want to solve it'. Every system has
some constraints in it that we have to live with, but in most
cases it does not prevent you from doing what you want to do, if
you just take a different view of the situation.

Jim Holtman

mccaugh@s.cs.uiuc.edu (08/25/89)

I'm sorry if I offended anyone by my 'correction' - I certainly didn't mean to:
the results reported for the SNOBOL IV programs were indeed correct, I was just
trying to shed a little light...I thought the whole discussion was interesting
in pointing out SNOBOL's multiple entry-point behavior---thanks for bringing
that out!

bengsig@oracle.nl (Bjorn Engsig) (08/28/89)

Article <207600032@s.cs.uiuc.edu> by mccaugh@s.cs.uiuc.edu says:
|
[some code in a language (was it SnowBall? :-) unknown to me deleted]
|
[some stuff about a '$' operator deleted]
|I really don't mean to sound pedantic
I don't know if you are pedantic, but I know for sure that this has nothing
to do with C.

Could we please stop this discussion about main.
-- 
Bjorn Engsig, ORACLE Europe         \ /    "Hofstadter's Law:  It always takes
Path:   mcvax!orcenl!bengsig         X      longer than you expect, even if you
Domain: bengsig@oracle.nl           / \     take into account Hofstadter's Law"

karl@haddock.ima.isc.com (Karl Heuer) (09/02/89)

In article <2634@trantor.harris-atd.com> bbadger@x102c.harris-atd.com (Badger BA 64810) writes:
>Well, it really is only a small detail, but it is a completely unnecessary

Clearly *some* method is necessary to indicate where execution should begin.
I happen to think that invoking a function with a known name is the most
elegant solution I've seen so far.

>If the burden of proof was on putting ``main()'' into a new language, instead
>of taking it out of a language, how would you stand?

That was addressed to Doug, but I'll answer it anyway.  I'd put it in.

But I see it the other way around; it's not so much a matter of "adding main()
to the language" as "removing PROGRAM from the language".  It's simpler.  In
FORTRAN, you've got three types of subprogram: functions, subroutines, and the
main program.  In C, all three are combined into a single uniform entity.  I
consider this a plus.

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

tneff@bfmny0.UUCP (Tom Neff) (09/02/89)

Here's the thing about C standardizing on main() as an entry point.
While the occasional need to circumvent this is legitimate, the
situations where this need arises are NOT portable.  And most of the
sophisticated C implementations or hosting environments I've encountered
do provide you with a (non-portable) way of tweaking your entry point if
you understand the tools well enough.  (Either you can edit and
re-assemble the front end startup code that calls main(), for example,
or the linker has options to rename symbols or designate alternate
entry points... or something else.)

So people with a real need for this can generally get it done.  Meanwhile
it's quite useful to have a well defined standard entry point for the
remaining huge majority of normal cases.
-- 
Annex Canada now!  We need the room,	\)	Tom Neff
    and who's going to stop us.		(\	tneff@bfmny0.UU.NET

bbadger@x102c.harris-atd.com (Badger BA 64810) (09/03/89)

In article <14506@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article [...] (Badger BA 64810) writes:
[...]
>>If the burden of proof was on putting ``main()'' into a new language, instead
  ^^ Note well!!
>>of taking it out of a language, how would you stand?
>
>That was addressed to Doug, but I'll answer it anyway.  I'd put it in.
>
>But I see it the other way around; it's not so much a matter of "adding main()
>to the language" as "removing PROGRAM from the language".  It's simpler.  In
>FORTRAN, you've got three types of subprogram: functions, subroutines, and the
>main program.  In C, all three are combined into a single uniform entity.  I
>consider this a plus.
>
>Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

I know the burden of proof lies on the side proposing a change.
That's why I said ``if''!  It was a HYPOTHETICAL question.

I want to address the ``main()'' issue from a clean slate to see if
there is any reason to *put it in* the language.  Again, this is
hypothetical, so you can no longer say, ``That's the way it was always
done before.''  

Here's my list of reasons *for* using ``main()'':
1)  It's very simple.  Just have the linker call _start_up, and have
crt0.o call main().
2)  ``main'' is mnemonic.  It's easy to remember.
3)  ``main'' is short, and easy to type.  Better than ``startup_routine''
  for instance.

Reasons like, 
  o ``FORTRAN and Pascal have a single main program.''
  o ``All my C books say `main()' is the main procedure.''
  o ``It's not portable.  I won't be able to use the new code on REAL C.''
  o ``All my REAL C code won't work with the new compiler.''
are non-responsive. 

I'm asking the hypothetical question:
	If you had a language like C in every way except that a routine 
	called ``main()'' were treated exactly like any procedure with any
	other name, what reasons could you put forward for putting in the
	feature that every program must have a routine called
	``main()'' which will be the first and only routine called after
	startup is finished?

To help prevent off-the-track follow ups, let me state two things:

1) I'm not trying to actually change the way C works.  I know this is
a small detail in the language which can be trivially worked around.
It doesn't really matter much either way.  I'm sure there are lots of
really important things which are better subjects for _real_ standards
committees.  I just wonder whether it deserves a secure place in the
standard, because I can't see that the language would be any worse off
without it.

2) I think that most current C compiler front-ends *already* work the way 
I want: ``main()'' _is_ an ordinary function.  The fixation on main is 
only done in the linker or run-time support.  In support of this, I
note that ``A C Reference Manual'' by Harbison & Steele (1st ed.,
sorry) does not have an index entry for ``main'', neither does
``main'' show up in either syntax of C (app. B and app. C).  
program ::= { top-level-declaration }*
top-level-declaration :== function-definition | declaration 




    -----	-	-	-	-	-	-	-	----
Bernard A. Badger Jr.	407/984-6385          |``Get a LIFE!''  -- J.H. Conway
Harris GISD, Melbourne, FL  32902             |Buddy, can you paradigm?
Internet: bbadger%x102c@trantor.harris-atd.com|'s/./&&/g' Tom sed expansively.

flaps@dgp.toronto.edu (Alan J Rosenthal) (09/04/89)

bbadger@x102c.harris-atd.com (Badger BA 64810) writes:
>I just wonder whether it [main() being the entry point] deserves a secure
>place in the standard, because I can't see that the language would be any
>worse off without it.

Without it, you cannot write Hello, world portably!
"int main() { printf("Hello, world\n"); return(0); }" ??
No, it might not get run.

Remember that the purpose of the standard is to allow the writing of portable
programs.  That means that someone else can recompile your program somewhere
else without editing it and it will work and do the same thing it did for you.
The standard is not merely a guideline as to what is a good C implementation.

ajr

bagpiper@pnet02.gryphon.com (Michael Hunter) (09/05/89)

uhhh.....couldn't you fake a different entry point by not naming any function
main and then using the macro preprocessor to name something main.  
NOTE:  I am not suggesting this, nor would I do it...And god would I hat
to work with anybody's code that did this!!!!

Actually, I guess this doesn't answer the question of being able to define an
entry point at run time...oh well.

                                        Michael Hutner



UUCP: {ames!elroy, <routing site>}!gryphon!pnet02!bagpiper
INET: bagpiper@pnet02.gryphon.com

peter@ficc.uu.net (Peter da Silva) (09/05/89)

----cut here... rcc.c----
/* Special 'cc' for Herman Rubin. */
#include <stdio.h>

/* usage: rcc entry-point cc-options */

main(ac, av)
int ac;
char **av;
{
	FILE *fp;
	char *cc;
	char *getenv();

	if(ac < 2) {
		fprintf(stderr, "%s: missing argument\n", av[0]);
		exit(2);
	}

	if(!(fp = fopen("real_main.c", "w"))) {
		perror("real_main.c");
		exit(1);
	}

	fprintf(fp, "main(ac, av, ep);\n");
	fprintf(fp, "int ac;\n");
	fprintf(fp, "char **av, **ep;\n");
	fprintf(fp, "{\n");
	fprintf(fp, "\treturn %s(ac, av, ep);\n", av[1]);
	fprintf(fp, "}\n");

	fclose(fp);

	cc = getenv("CC");
	if(!cc) cc = "cc";

	av[0] = cc;
	av[1] == "real_main.c";

	execvp(cc, av);

	perror(cc);
	exit(1);
}
-- 
Peter da Silva, *NIX support guy @ Ferranti International Controls Corporation.
Biz: peter@ficc.uu.net, +1 713 274 5180. Fun: peter@sugar.hackercorp.com. `-_-'
"The Distribution: field on the header has been modified so as not to      'U`
 violate Information Export laws." -- eugene miya, NASA Ames Research Center.

tneff@bfmny0.UUCP (Tom Neff) (09/05/89)

In article <19474@gryphon.COM> bagpiper@pnet02.gryphon.com (Michael Hunter) writes:
>uhhh.....couldn't you fake a different entry point by not naming any function
>main and then using the macro preprocessor to name something main.  

Oh yes if you have the luxury of RECOMPILING then you can play all sorts of
tricks.  I have presumed right along that what these folks want is to decide
ex post facto where in an already-compiled set of object files you want the
program entry point to go.

In fact it's even easier if you have the luxury of REASSEMBLING the usual
front-end code which is REALLY invoked by the OS loader, and which then
calls main() as a normal subprogram.  Again, I assume people want to be
able to choose their entry point even without this ability.
-- 
Annex Canada now!  We need the room,	\)	Tom Neff
    and who's going to stop us.		(\	tneff@bfmny0.UU.NET

Tim_CDC_Roberts@cup.portal.com (09/06/89)

Let me give an example of a case where "main" as main program possibly
makes an inconvenience.
 
Take Control Data (...please).  On our systems, after compiling and
linking a set of object routines, you end out with an executable
file.  This executable can then be placed into a LIBRARY with many
other executables.  If all the executables have the same entry point
name (main or crt0 or _start_up or whatever), how do you designate which
executable in the current library you wish to invoke?
 
This is solvable, of course, by modifying the librarian to allow the user
to specify a main_program_name, or by using the file name instead of an
entry point.
 
I'm not advocating changing C.  Our scheme was developed when FORTRAN
(PROGRAM ABCD1), COBOL (ID DIVISION...PROGRAM-NAME IS ABCD2.), and
even Pascal (PROGRAM ABCD3;) were popular.  But adding C to the list
does require some rethinking.
 
Tim_CDC_Roberts@cup.portal.com                | Control Data...
...!sun!portal!cup.portal.com!tim_cdc_roberts |   ...or it will control you.
 

diamond@csl.sony.co.jp (Norman Diamond) (09/06/89)

In article <6030@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:

>/* Special 'cc' for Herman Rubin. */

...

>main(ac, av)

...

>	av[0] = cc;

Peter!  For shame.  You should know that you can't assign to that.

>	av[1] == "real_main.c";

Uh, this one you can do, but you can't do what you meant to do.

--
-- 
Norman Diamond, Sony Corporation (diamond@ws.sony.junet)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

peter@ficc.uu.net (Peter da Silva) (09/07/89)

In article <21897@cup.portal.com>, Tim_CDC_Roberts@cup.portal.com writes:
> Let me give an example of a case where "main" as main program possibly
> makes an inconvenience.
[describes executable library]

Sounds like a non-standard-extension situation, like what VMS C has to
do to support system include libraries and DEC's penchant for system
calls that have lots of dollar signs in them, or for that matter what
you do to implement any number of system-dependent objects (Mac desk
acessories, Amiga device handlers, etc...).
-- 
Peter da Silva, *NIX support guy @ Ferranti International Controls Corporation.
Biz: peter@ficc.uu.net, +1 713 274 5180. Fun: peter@sugar.hackercorp.com. `-_-'
"The Distribution: field on the header has been modified so as not to      'U`
 violate Information Export laws." -- eugene miya, NASA Ames Research Center.

karl@haddock.ima.isc.com (Karl Heuer) (09/09/89)

In article <10810@riks.csl.sony.co.jp> diamond@riks. (Norman Diamond) writes:
>>	av[0] = cc;
>Peter!  For shame.  You should know that you can't assign to that.

The pANS guarantees that the argv array is modifiable, as are the strings to
which its members point.  See 2.1.2.2.

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

diamond@csl.sony.co.jp (Norman Diamond) (09/13/89)

In article <10810@riks.csl.sony.co.jp> I wrote:
>>>	av[0] = cc;
>>Peter!  For shame.  You should know that you can't assign to that.

In article <14559@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:

>The pANS guarantees that the argv array is modifiable, as are the strings to
>which its members point.

Really?  OK, I believe you.  It used to be unsafe to try to modify.

>See 2.1.2.2.

This is very difficult.  Global Engineering Documents refused to sell
me one.  Anyone want to send me an illegal copy?

--
-- 
Norman Diamond, Sony Corporation (diamond@ws.sony.junet)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

mouse@mcgill-vision.UUCP (der Mouse) (09/16/89)

In article <21897@cup.portal.com>, Tim_CDC_Roberts@cup.portal.com writes:
> Let me give an example of a case where "main" as main program
> possibly makes an inconvenience.

> Take Control Data (...please).  On our systems, after compiling and
> linking a set of object routines, you end out with an executable
> file.  This executable can then be placed into a LIBRARY with many
> other executables.  If all the executables have the same entry point
> name (main or crt0 or _start_up or whatever), how do you designate
> which executable in the current library you wish to invoke?

> I'm not advocating changing C.  Our scheme was developed when FORTRAN
> (PROGRAM ABCD1), COBOL (ID DIVISION...PROGRAM-NAME IS ABCD2.), and
> even Pascal (PROGRAM ABCD3;) were popular.  But adding C to the list
> does require some rethinking.

main() is a specification of how the *C source code* specifies the main
entry point.  It does not necessarily imply that the symbol table of
the output file (assuming there is such) contains anything bearing any
resemblance to "main".  A C compiler on your CDC system would be
perfectly justified in recognizing the name "main" specially and
producing, instead of a normal symbol table entry, a name derived
somehow else (the name of the source file, perhaps?) and marked as
"main entry point", the same as would be produced by FORTRAN or Pascal
for a PROGRAM, for PL/I's PROC OPTIONS(MAIN), etc.  (I don't know
whether main() is required to work if called recursively or not; if so,
the compiler would have to recognize the name "main" in certain other
contexts as well.)  All that's required is that there be no possibility
of this special symbol table entry preventing the user from writing a
routine which happens to have the same name as the source file (for
example).  Nothing insurmountable.

					der Mouse

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