I agree, for different reasons, that this part of the standard
is ungood and in fact pretty meaningless. However, it's
there. And seems to survive into C++0x.
And no implementation actually tries to take advantage of it. I
don't know of any that defer initialization until after the
first statement in main.
No, I don't think it can be intentional.
It is.
The intent is to make dynamic linking conforming. Of course,
the wording still doesn't succeed in that, even with regards to
initialization, and there are many other places where dynamic
linking introduces undefined behavior, but as it happens, I
happened to campaign to get this statement removed, on the
grounds that it couldn't be implemented, and caused real
problems with existing code, and the reason given me as to why
it stayed was dynamic linking.
int main()
{
return myCppMain();
}
"after the first statement in main" would here mean after the
program's finished.
Or never, if nothing in the translation unit of the static
variable is ever used. Although you're right that "after the
first statement of main" really means after the first statement
of main has finished, which leads to some interesting problems
as well. The intent is very much "after you're into user
written code in main".
The original phrase (more or less) goes back to the ARM, and the
intent there was clearly to speed program start up, by not
requiring static initialisers to be executed until other code in
the module was needed, and thus, the module was paged in; at the
time, the specification of <iostream.h> required it to contain a
static variable with dynamic initialization, which meant that on
program start up, you'd get a page hit for every module which
included <iostream.h>. On the systems at the time, that could
be very noticeable.
The standard dropped the requirment concerning the static
variable; I don't know if this was intentional or through
oversight (when the previously single header was split up into
several distinct headers), but a lot of implementations (e.g.
g++, STL port) of <iostream> do define the static variable, even
if it is no longer required. And I don't notice complaints
about start up speed from them today. So maybe the issue isn't
relevant on today's machines (or maybe people concerned with
performance are simply using other compilers).
The left brace is not a statement, and empty statements in C++
have to be explicitly introduced via ";".
My reading is that the intention is that initialization can
occur after the left brace of the main function's function
body, /before/ the first statement, but not later, just as in
your CFront-example above. I can't make sense of anything
else.
I didn't say it made sense. I said that it was the intent.
Conceptually, in the CFront-example, the initialization takes
place before entering main---at least with regards to anything
that a conforming program can tell. Or if you prefer, it is
what happens when you "execute" the opening left brace of main.
A sort of extended function prefix, so to speak---instead of
just setting up the local stack frame, the compiler generates
code to call the initializers, then set up the local stack
frame. There is explicite wording in the standard to allow
this, but it is elsewhere: the fact that, unlike in C, you are
not allowed to call main from your code.
There is no way a conforming program can determine whether the
initialization was the last thing before calling main in crt0
(or whatever the implementation calls its start-up code), or the
first thing in main (before any of your code is executed).
Both Unix and Windows do object specific initialization when
you dynamically load an object. There's no difference in
them there. Both also have many different options with
regards to what is or is not visible in the various
"modules". The main differences are, I think, that 1) all
of the options in Windows are compile and link time---you
don't have any choices at load time,
What does this mean? What choices can be specified at load
time for *nix shared library?
Whether the global symbols in the object are available when
loading other dynamic objects or not. (Specific implementations
of dlopen may have other options, but this basic choice is
specified by Posix.)
I'm not sure what you mean here.
I'm not that sure of the terminology myself; by "root", I mean
the code loaded as the initial binary image, before any dynamic
objects have been loaded. When you load a dynamic object under
Unix (using dlopen), you must specify either RTLD_GLOBAL or
RTLD_LOCAL: in the first case, all of the globals in the dynamic
object become accessible to other dynamic objects, in the
second, no. But since it's the operating system which loads the
root, you can't specify anything there. Under Unix, the global
symbols in the root are available to all other dynamic objects,
as if it had been loaded specifying RTLD_GLOBAL. Under Windows,
if I understand correctly, the root is always loaded as if
RTLD_LOCAL had been specified (and the choice for other
dynamic objects is made when they are build, rather than when
they are loaded---but I'm not really that certain about anything
in the Windows world).
But anyway, Windows DLLs enjoy a good degree of decoupling
because there are two sets of symbols: symbols linked by the
ordinary language-specific linker, which are only visible
until the DLL has been created, and symbols linked by Windows
loader, which are the subset of the former set that are
explicitly exported or imported. All the rest, e.g. the DLL's
usage of some runtime library, is hidden.
That's more or less true under Unix as well, depending on the
options. Of course, the linker under Unix isn't standardized,
and Posix allows an implementation to add any number of
additional options to dlopen, so different Unix will have
different capabilities here; Solaris, at least, offers the
possibility of exporting symbols on a symbol by symbol basis,
creating groups of dynamic objects, with symbols visible within
the group, but not elsewhere, and who knows what else.
Historically, Unix dynamic linking was developed to allow the
sharing of object files, and by default, it tries to behave as
much as possible like static linking. But in practice, it works
very well for things like plugins (where you want a maximum of
isolation) as well, and today is probably used more for this and
for versioning than for pure sharing.
Not sure what you mean by "DLL dynamic storage", and even if I
did understand that term I suspect that I wouldn't understand
the complete sentence, ending with "unless you want to". What
I wrote about was per-thread storage, and problems with that
in the context of automatic initialization and cleanup calls
from OS.
I thought you were talking about the common complaint that you
can't free memory in a different DLL than the one it was
allocated in. Which in fact depends on how you link; the
Windows specialists here have no trouble with it, for example.
[...]
I'm not convinced that it is, in the sense of migration to
C++.
However, I think it could be good engineering in the sense of
using C++ as a "restricted C", i.e. a C with more strict type
checking.
No. Although that too is IMHO a good step. But a large
application will likely be organized into many sub-systems, and
in general, management prefers that when reworking one
sub-system, you not touch any other.
A C program has a much more procedural structure than proper
C++ code, and replacing parts with C++ means forcing use of
C++ in procedural, non-OO mode.
It depends on the C. Long before I'd ever heard of C++, the way
I structured C was to define a struct and a set of functions
which manipulated it, and cross my fingers that no one
manipulated the struct other than with my functions. From what
I can see in third party libraries today, this seems to be more
or less common practice.
It's difficult to understand the first sentence here, which is
seemingly a tautology. One must assume that what you mean is
that "XCOM or similar technologies do not provide any
significant advantage for ...", for what?
You have an existing interface, defined in C. You reimplement
the sub-system in C++, using classes, and defining an interface
which uses classes. You then implement the C interface,
forwarding to the new classes.
I'm not familiar with XCOM, but I don't think that this is
similar. (It's obviously a lot easier if the original
application did use some sort of isolation layer, like Corba or
XCOM. But most don't.)
However, technically it should be no big deal to write
extern "C" int c_language_main( int, char*[] );
int main( int argc, char* argv[] )
{
return c_language_main( argc, argv );
}
and compile that top-level as C++.
Technically, no. Practically, it depends. There may be
very good reasons for not doing so.
Such as the fact that you don't have access to the main. It's
not part of the sub-system your group is responsible for.