[comp.lang.c++] Again: Access to argc,argv outside main

dingelde@sherekhan.uucp (Dennis Dingeldein) (10/25/90)

/* 

Hello again,

This Code refers to my original posting. 
I asked there
	HOW DO I ACCESS ARGC AND ARGV OUTSIDE MAIN ?

I've got only anwers of the
type "You can't do anything before entering main(), main() is the
entry point and first thing ever executed". To show that this is
wrong, I send a small test. This demonstrates calling Methods/Functions
before entering main().

The code shows that global objects are created before main() is
entered. 
So there is still the problem I described originally:

	HOW DO I ACCESS ARGC AND ARGV OUTSIDE MAIN ?

Perhaps there is no solution to this problem. Then, is it due to
my compiler (g++ 1.35.1), due to me, due to C++-Design ?

   The following code was compiled with g++

   It defines a class ("A") and create two objects of this class.

   The first Object ("I_will_be_called_before_main") tries to
   access argc, argv as mentioned by friendly people.
   Of course, this do not print argv[0], because this object
   actually is created *before* entering main.
   But at that time main() is not yet entered, and global_{argc,argv} are
   not yet defined.

   The second Object "I_will_be_called_after_main" is inside main(), 
   and the lines above do
   initialize global_{argc,argv}. So there I get the expected result, i.e.
   argv[0].

*/
   
#include <stdio.h>

int global_argc = 0;
char **global_argv = NULL ;

// a class
class A {
public:
	A();
};

A::A() {
	printf( "argc: %d ", global_argc );
	if (global_argc!=0) 
		printf( "argv[0]: %s", global_argv[0] );
	printf( "\n" );
}

// the test program

// an object - outside main() - creates only zero, no argv
A I_will_be_called_before_main ; 

main( int argc, char **argv ) {

	// at first set up argc, argv
	global_argc = argc ;
	global_argv = argv ;
	// an object -  inside main() - creates only 1, and argv[0]
	A I_will_be_called_after_main ; 
}
Dennis Dingeldein	ZGDV Zentrum fuer Graphische Datenverarbeitung
(dingelde@zgdvda.uucp)	Wilhelminenstr. 7 		    wMw
			D-6100 Darmstadt, West Germany	    ~.~
			Phone: +49/6151/155-101		    \-/

rwhite@nusdecs.uucp (0257014-Robert White(140)) (10/31/90)

The primary problem you will expeirenc trying to access argc and argv
is that they are standard refrences to a variable phenominon.  The
independant variable being the operating system, the dependant
variable being the compiler library, and the outcome only being
garenteed at a single point... the invocation of main.

In C the initalization sequence is basically (no flames please):

	1. True Static data.  This is usually part of the load image.
	2.	Procedural Startup Code.  Provided by the compiler/library.
	3. Invocation of _main().

It should be aparent that the presence of arguments to main would be
established durring the invocation step (as with any C function call)
and there is no comentary as to how the data needs must be represented
prior to that time.

It is obvious that the data does indeed exist prior to that time, but
the shape of the data (argc, argv, and envp for some) is not
necessarily useful.  It is often unparsed or living in one or more
system areas somewhere.  And, as such it is most likely easier and
maybe even best left alone until after the invocation of _main().

Generalizing this to C++, you are informed that the constructors of
static objects, which are not always actual function-call events (if
the constructor is just simple assignments the object may be converted
to true static data and initalized by the module loader ??), will be
'called' "before the invocation of main."  Given that a global
instance of argc and argv are/should be in identical format to the
real arguments (I guess on this one) I, as a theoretical compiler
writer, would have left the invocation code for main alone except for
the copying of the argc/argv into the global area.  This, in turn
implies that argc and argv do/will not ever be likely to exist in that
form durring the constructors of static objects.

Indeed there may not be an actual copy of the arguments at all.  The
stack frame for _main() is (by implication) garenteed to be "in scope"
for the entire execution period of the program proper, and argc/argv
may be refrences back into the real(tm) stack frame for _main().  You
might be able to test this by assigning to the globals and then
testing the locals (I don't know wether argc/argv are constant).
Reguardless of the test, any system whare that is the case will, by
definition, procribe the globals from existing durring the constructors
because the stack fram where they would be put is occupied by the
constructors frames themselves.

REAL WAG (wild ass guess) HERE:  cfront, because of the way it must
produce "normal" C code, may replace your main function with a dummy main
that calls the constructors and then calls the original (now
name-munged) main().  You might be able to edit the C code so
prodeuced to sneak the arguments to your constructor, but this would
be a real pain to maintain.  Obviously not an available practice on
native-code C++ compilers.

Your choices are feiw and simple (barring the wag):
	1. Get and change the library code to make the globals exist before
	constructor calls.

	2. Extract the args for the OS yourself.

	3. Make a portable work-around.

	4. (something I havn't thought of yet ;-)


Number 3 is my best recomendation (at least until 4 comes around).  I
would suggest a static refrence class for the args which will fufill
the minimum requirements of the other static objects and which you can
backfill with the real(tm) arguments.  (possibly even causing it to
wander out and reinitalize the dependant static objects).

Better yet, only declare static pointers to the requsite objects and
put off *all* your now-so-called static objects until after main() is
in scope, making main() a container function for:
{
	initalizations(argc,argv);
	real_logic(argc,argv);
	cleanup();
}
and move your current main() into real_logic().  (This is OOP after
all).

Really depends on your real need.

Rob.