cross-stack globals, also, file inclusion

Joel Rees joel at
Mon Oct 27 22:48:38 EST 2003

Since I started this mini-monster of a thread, I suppose I should
comment somewhere along here.

Maybe it will help if I wax pedantic. (Heh.) The problem is where to
start. Hmm.

There are several kinds of constants, and there are more "times" than
compile and run, as it were.

C, incidentally, has in effect three compile phases (minimum), which
occur before run time: 

The first phase is actually a macro-pre-processing phase. It allows you
to define string replacements, and it performs the string replacements.
(The string replacement language is actually a separate language from C.)

The second phase is what one traditionally expects of a compiler, it
takes lines of C and converts it to something fairly close to machine
code. (Traditionally, it outputs assembly language code, which must then
be further processed. It may also involve some machine-independent
intermediate form. It usually also includes some optimizations.)

The third phase links the compiled code to pre-compiled library code and
loads the mess into main memory, where it can be executed. (Again, this
is usually divided into multiple steps, since static libraries are
pre-linked before distribution of the app, and dynamic libraries are
linked at load time, which, in a GUI is a few milliseconds after you
double-click the app's icon.)

Run time begins after all load-time processing.

The constants that have been getting most of the attention in the thread
are the sort of constants that are processed during the second phase.
They are basically variables which the compiler enforces a no-write rule
on. (C did not have such a thing for the first ten or so years.)

Accessors are generally associated with constants that are processed (in
effect) during the third phase, or, for pseudo-constants, at actual

So, is it possible to have constants that are processed in the first
phase? Of course: 

    #define MAX_GENIUSES 42

Then the pre-processor behaves like a text editor doing a global
search-and-replace, putting in the constant source text 42 in everywhere
the source had MAX_GENIUSES. This is purely semantic convenience,
because you probably would have no idea what 

    for ( i = 0; i < 42; ++i )

was trying to do, where 

    for ( i = 0; i < MAX_GENIUSES; ++i )

lets you guess that the program is working through a list of (putative)
geniuses. The programmers see MAX_GENIUSES, the compiler sees the
literal constant 42, and generates code to load the literal constant.

Barring games with the pre-processor, 

    const int k_maxGeniuses = 42;

will be processed in the second, or perhaps third phase. Depending on
compiler optimization, the code executed at run-time is likely to be a
load of a literal constant.

Now, an accessor function

    int get_maxGeniuses() { return 42; }

will be seen as a function call, although aggressive optimization might
actually strip out the call and leave just the load of the literal.

Perhaps, the effect of the differenct phases might be seen by the
following patchwork:

    #define MAX_GENIUSES 42

    const int k_maxGeniuses = MAX_GENIUSES;

    int get_maxGeniuses() { return k_maxGeniuses; }

Assume the first line is in a header file, which the pre-processor
brings in in the first phase by way of the #include directive. The
second line is in the definition of a library function, which is (in
this example) linked in during the third phase. The third line is in the
application source, and is eveluated at the actual run time (because I'm
arbitrarily disabling aggressive optimization in this example).

(Why go to Toledo via Moscow? Because your girlfriend is in Moscow and
the wedding is in Toledo. Just joking. ;-)

Why would you want to do this? (Let's see if I can invent something
reasonable here.)

Say you have a file called people.h, and MAX_GENIUSES is defined there
as the maximum number of geniuses your company is allowed to employ.
Then you have a library that you share with a sister company, perhaps
called hiring_standards, and the k_maxGeniuses is defined in there. When
your company compiles it, k_maxGeniuses comes out 42, but when the
sister company compiles it, k_maxGeniuses comes out 67, because they use
their own people.h header.

You can share source without a huge case statement saying something like

    if your_company 
      k_maxGeniuses = 67 
      if my_company 
        k_maxGeniuses = 42
      end if
    end if

Rev's switch statement would be reasonably compact, but compactness is
not the object. How do you share the file that case statement is going
to be in with your sister company, without the advantage of code reuse
being wiped out by all the

So, now that I've gotten rid of some stress by waxing pedantic, when I
get a chance, I'll have to check out rev's properties, to see if
properties in a common sub-stack or something similar will do the trick.

Joel Rees, programmer, Systems Group
Altech Corporation (Alpsgiken), Osaka, Japan

"When software is patentable, anything is patentable." 

More information about the Use-livecode mailing list