Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!seismo!gatech!bloom-beacon!think!ames!ptsfa!ihnp4!homxb!mtuxo!mtune!codas!cpsc6a!rtech!wrs!dg
From: dg@wrs.UUCP (David Goodenough)
Newsgroups: comp.lang.c
Subject: Re: Accessing argc & argv from a function
Message-ID: <253@wrs.UUCP>
Date: Fri, 17-Jul-87 14:14:11 EDT
Article-I.D.: wrs.253
Posted: Fri Jul 17 14:14:11 1987
Date-Received: Sun, 19-Jul-87 01:19:21 EDT
References: <22@flmis06.ATT.COM>
Reply-To: dg@wrs.UUCP (David Goodenough)
Organization: Wind River Systems, Emeryville, CA
Lines: 89

In article <22@flmis06.ATT.COM> mikel@flmis06.ATT.COM (Mikel Manitius) writes:
>I recently ran accross an interresting question.
>
>How does one get at argc and argv (and possibly envp) from a function?
>Without declaring it in main first, and then passing a pointer (global
>or not)! Assume you don't have control over what happens in main. Can
>you still get at the argument vector?
>-- 
>				Mikel Manitius @ AT&T Network Operations
>				mikel@codas.att.com.uucp | attmail!mikel

In a sentence - you could, but it would be a real mess, and extremely
system dependant. To show *EXACTLY* what happens, here is the
stack (from a PDP-11, 68K, VAX, Z80, and probably 80*86) just after
entry to main:


		|		 |
		|      envp	 |	<------ these are the ONLY
		+----------------+	<------ references to argc etc. that
		|      argv	 |	<------ exist in the memory space
		+----------------+	<------ of the program, so you've
		|      argc	 |	<------ GOT to use them or do without
		+----------------+
		| return address |
		|    from main   |
		+----------------+
		| previous stack |
frame pointer ->|  environment   |
		+----------------+
		|   locals for   |
		|      main      |

Since argc, argv, and envp can only be accessed at this location, you have
two options: get at them as arguments to main (nice and clean), or where
ever it is you want them do something like:


getargs()
 {
    int i;

    static int *ip;		/* note the static */

    static struct frame
     {
	char *return;
	struct frame *previous;
     } *fp;

Now, since i is the only automatic local (this is the reason for ip & fp
being static),

    ip = &i

will set ip to point to one int below the current frame pointer. NOW

    fp = (struct frame *) &ip[1];

points fp at your current frame, and all you have to do is chase back up
the stack till you find whatever it is you're looking for. NOTE that this
is a kludge that I *DO NOT* recommend to anyone, because it will be so
unportable as to give most programmers a nervous breakdown. Also I don't
know how you'd set about detecting when you hit main. Once you do,
something along the lines of:

    ip = (int *) fp;

points ip back into the stack at main's locals (i.e. argc etc.) and indexing
off ip can get you what you want. Not very pretty you'll agree :-). As an
aside, I saw this used JUST ONCE in BCPL, which is a predecessor of C. It
did work in that environment because BCPL runs with two stacks: one growing
from high memory down contains constant sized frames, and another growing
from low memory up holds the locals. As a result of this, chasing up the
frame stack was not as traumatic as in C.

P.S. this second suggestion is NOT meant to be taken too seriously, it
is more an explanation of why you should simply try to get the stuff
out of main: as you say either by passing parameters, or by using
globals. As an aside, if you have source for the UNIX library look
at getenv, because somehow or other it does about what you're after, and
I'm damned if I know how it works.
--
		dg@wrs.UUCP - David Goodenough

					+---+
					| +-+-+
					+-+-+ |
					  +---+