Re: Need to create a C lib - using C++ classes - is it possible
* James Kanze:
On May 25, 1:34 pm, "Alf P. Steinbach" <al...@start.no> wrote:
* James Kanze:
On May 25, 5:53 am, "Alf P. Steinbach" <al...@start.no> wrote:
* Angus:
We have a lot of C++ code. And we need to now create a
library which can be used from C and C++. Given that we
have a lot of C++ code using classes how can we 'hide' the
fact that it is C++ from C compilers?
The C++ code will need the C++ runtime library.
Good point. If you don't use any standard components from the
library, nor new, nor typeid, maybe not, but then what's the
point.
Within the standards of C and C++ the only way to achieve that
is to insist that the C code using the library is called from
a C++ main program.
No. There are two separate issues involved here. Neither the C
nor the C++ standards say anything about how the compiler is
invoked; to get the C++ library with gcc, for example, you can
either invoke it as g++, or specify the library explicitly
(-lstdc++, with the normal Unix linkers). Formally, the C++
standard requires that main() be written and compiled in C++, or
you have undefined behavior.
That last sentence contradicts the "No" at the start.
The "no" referred to the statement that "the only way to achieve
that [the presence of the C++ runtime library] is to insist that
the C code [...] is called from a C++ main program." IMHO, it's
probably a good idea to do so, and will make things easier, but
the whole business of invoking the linker and making sure you
get the right libraries is implementation defined.
Implementation defined things are not defined by the C++ standard.
As I recall I wrote "within the standards of...", which you snipped in this
latest quote.
Checking earlier quotes above. Yep, that's what I wrote. And now you maintain
that some way that is "implementation defined" is guaranteed by the standards?
Anyway, this is a FAQ item,
<url:http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.1>
"You must use your C++ compiler when compiling main()
(e.g., for static initialization)"
and as you note also it's stated by the Holy Standard that
static variables may be (dynamically) initialized after entry
of main(), which implicitly requires a C++ main().
Woah. There's a definite misunderstanding here. The C++
standard has a somewhat twisted explination concerning how
static variables may be initialized after entering main, but it
is in practice unimplementable, and can effectively be ignored.
Static variables are initialized before entering main.
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.
The issue here is what that actually means. Some compilers
(including CFront) do (or did) recognize the name main, and
generate special code for the function, which called the
function which did global initialization. Conceptually, this is
still "before entering main", since it is before any statement
you write in main will be executed. But of course, it *does*
require that main be compiled with the C++ compiler in order to
ensure static initialization.
But this is an implementation constraint, not a standard
constraint. The standard doesn't really say anything about how
you link C and C++ (or even how you link C++ with other C++).
Very few implementations today have this constraint. But they
have other constraints (invoke the linker with g++, rather than
gcc, for example). The whole point is that just about anything
you try to say about this issue is implementation defined.
Even though that part of the standard is IMHO defective,
talking about "after the first statement of main" instead of
entry of main.
It's defective, because the constraints that it places on the
implementation in this case are impossible to meet. But the
"after the first statement in main" is very intentional;
No, I don't think it can be intentional.
int main()
{
return myCppMain();
}
"after the first statement in main" would here mean after the program's finished.
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.
what
happens before, and where, can simply not be determined by a
conforming program.
Huh?
[snip]
In Windows an alternative is to have the library as a DLL,
because Windows DLLs are more decoupled.
That sort of works in Unix, as well, if the C++ standard
library is also a DLL. (Which is generally NOT recommended,
of course.)
Well, the Windows situation is sort of opposite. Windows
dynamic libraries are strongly decoupled modules. In
particular, the OS provides automatic per-DLL initialization
and cleanup calls, so a DLL is almost free to use whatever
(the main problem with this scheme has to do with
per-thread-per-DLL storage).
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?
and 2) symbols in the root are not available to
dynamically loaded objects under Windows, and are always
available to dynamically loaded objects under Unix.
I'm not sure what you mean here. 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.
Other than
that, it's largely a question of which options you choose. (And
you certainly don't have per DLL dynamic storage under Windows
unless you want to. I know that the Windows applications where
I work don't have it.)
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. If you want details I'll have to look it up (it's about ten years ago
I dealt with that), but essentially, MSVC's built-in support for thread-local
storage doesn't quite work with dynamically loaded DLLs, so that DLLs are not
quite 100% independent modules where you can do absolutely anything you want.
[...]
The best is to forget that silly idea. Using C library from
C++, OK. But C++ has additional requirements from runtime
library, so other way, generally !OK, unless you're working at
a low level where you wouldn't have to ask...
It's actually a frequent requirement, and the original posters
question reflects one of the more common ways of migrating to
C++.
Ouch. :-)
It's very backwards, in many ways: structurally,
learning-wise, safety, simplicity. Just think about it. The
programmer is trying to implement a type safe little part of
the program in C++, but since using C as main language doesn't
even manage to do this in a good way or learn the Right
Things, then to top it off throws away all that hard-won type
safety and language-enforced correctness by using this part
only via a non-enforcing C language interface.
The company has a large application written in C. They're not
going to rewrite the whole thing. As subsystems get rewritten,
they're rewritten in C++. It's just good engineering.
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.
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.
I guess with proper insulating abstractions, like XCOM, it
could be better, but when the aim is to "migrate" to C++ I
doubt such abstractions will be in place.
You don't need XCOM. You do need to provide two interfaces, a
C++ interface (which will be used by new code, written in C++),
and a C interface which is compatible with the previous C
interface. But then, you usually have to ensure backwards
compatibility anyway.
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?
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?
Cheers,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?