For Programmers: Free Programming Magazines  


Home > Archive > VC STL > March 2006 > Problem with reading an int with operator>>









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Problem with reading an int with operator>>
andreas fabri

2006-03-11, 3:58 am


Hello,

I can't read an int as follows
int n, m;
char c;
std::cin >> n >> c >> m;

if the two ints are separated by a comma.
The problem is that somethig seems to be
wrong with the locale which seems to interpret
the comma as thousandsep.


According to a posting by Plaugher in comp.lang.c++.moderated
with the subject locale and streams on VC8
http://groups.google.fr/group/comp....1cda4688cd1bbe0

this is a bug in VC8. Plaugher also proposes a fix, but
it didn't work for my example.

Is there a service pack for VC8 that solves this rather
fundamental problem.

best regards,

andreas
P.J. Plauger

2006-03-11, 7:57 am

"andreas fabri" <andreasfabri@discussions.microsoft.com> wrote in message
news:1A1B4A26-081B-4E4E-9313-5D6B0938F233@microsoft.com...

> I can't read an int as follows
> int n, m;
> char c;
> std::cin >> n >> c >> m;
>
> if the two ints are separated by a comma.
> The problem is that somethig seems to be
> wrong with the locale which seems to interpret
> the comma as thousandsep.
>
>
> According to a posting by Plaugher in comp.lang.c++.moderated
> with the subject locale and streams on VC8
> http://groups.google.fr/group/comp....1cda4688cd1bbe0
>
> this is a bug in VC8. Plaugher also proposes a fix, but
> it didn't work for my example.


Probably because you're using the flawed version built into a DLL, not the
changed version in the edited header file.

> Is there a service pack for VC8 that solves this rather
> fundamental problem.


I hear that one is in the works, but I don't know of any publicly announced
release date.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com


andreas fabri

2006-03-12, 7:00 pm



"P.J. Plauger" wrote:

> "andreas fabri" <andreasfabri@discussions.microsoft.com> wrote in message
> news:1A1B4A26-081B-4E4E-9313-5D6B0938F233@microsoft.com...
>
>
> Probably because you're using the flawed version built into a DLL, not the
> changed version in the edited header file.
>
>
> I hear that one is in the works, but I don't know of any publicly announced
> release date.
>
> P.J. Plauger
> Dinkumware, Ltd.
> http://www.dinkumware.com
>
>
>


Thanks for the reply.
Is there a workaround, so that I dont use the precompiled dll?
Can I recompile it (but what?) ?

It might be worth to add the example program to a regression
test. It's almost unbelievable to have such a bug in VC8, or
the STL shipped with the compiler.

andreas
P.J. Plauger

2006-03-12, 7:00 pm

"andreas fabri" <andreasfabri@discussions.microsoft.com> wrote in message
news:B3C8648E-DCDE-4731-B645-77AC49468B93@microsoft.com...

> "P.J. Plauger" wrote:
>
>
> Thanks for the reply.
> Is there a workaround, so that I dont use the precompiled dll?
> Can I recompile it (but what?) ?


I'm not sure that you can statically link at all these days. The only
trick I can think of, which is pretty unpalatable, is to make a
stream that doesn't look like istream<char, char_traits<char> >,
probably by writing your own traits class. That would outsmart
the prebuilt facets in the DLL. But that may well lead to other
surprises.

> It might be worth to add the example program to a regression
> test.


I'm sure that's been done.

> It's almost unbelievable to have such a bug in VC8, or
> the STL shipped with the compiler.


As I've explained before, the bug arose from the collision of
two "Friday afternoon edits" -- changes to the C++ Standard
that were made with no supporting committee resolutions.
Fixing one problem made the code vulnerable to the other.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com


David Wilkinson

2006-03-13, 7:58 am

P.J. Plauger wrote:

[snip]

> I'm not sure that you can statically link at all these days. The only
> trick I can think of, which is pretty unpalatable, is to make a
> stream that doesn't look like istream<char, char_traits<char> >,
> probably by writing your own traits class. That would outsmart
> the prebuilt facets in the DLL. But that may well lead to other
> surprises.


PJ:

I don't think it's true that you can no longer static link in VC8. I
think it is just (even) more discouraged than before because you cannot
static link if you're using /clr.

One of the many things I like about static linking is that I can patch
the standard library myself (this is important in VC6, where the patches
never made it into the service packs).

But I have a question. What exactly is compiled into msvcp60.dll (and
corresponding VC7/8 versions)? Is it just std::string and std::wstring?
And what exactly is the purpose of it? Is it just so these objects can
be passed across DLL boundaries? Personally, I would be prepared to
forgo this advantage if I could keep all my Standard Library in the
headers where it could be easily updated. Is it possible to do this even
if one is dynamically linking CRT (and MFC)?

It seems to me that the existence of msvcp60.dll (and VC7/8 versions) is
an impediment to Microsoft updating the standard library when
improvements have been found. Or am I missing something here?

David Wilkinson


P.J. Plauger

2006-03-13, 7:58 am

"David Wilkinson" <no-reply@effisols.com> wrote in message
news:%23%23EdNpoRGHA.5900@tk2msftngp13.phx.gbl...

> P.J. Plauger wrote:
>
> [snip]
>
>
> PJ:
>
> I don't think it's true that you can no longer static link in VC8. I think
> it is just (even) more discouraged than before because you cannot static
> link if you're using /clr.


Could be. I cloud over when the subject of DLLs comes up, and defer
to people like Pete Becker whenever possible.

> One of the many things I like about static linking is that I can patch
> the standard library myself (this is important in VC6, where the patches
> never made it into the service packs).


I absolutely agree, and prefer static linking in most contexts.

> But I have a question. What exactly is compiled into msvcp60.dll (and
> corresponding VC7/8 versions)? Is it just std::string and std::wstring?


Grep the headers for all the DLL magic. You can see the classes that
are explicitly instantiated into the DLL.

> And what exactly is the purpose of it? Is it just so these objects can be
> passed across DLL boundaries?


Well, it does save link time and code size in .exe files.

> Personally, I would be prepared to forgo
> this advantage if I could keep all my Standard Library in the headers
> where it could be easily updated. Is it possible to do this even if one is
> dynamically linking CRT (and MFC)?


Dunno. I'd like to think so.

> It seems to me that the existence of msvcp60.dll (and VC7/8 versions) is
> an impediment to Microsoft updating the standard library when improvements
> have been found. Or am I missing something here?


I think Microsoft takes a more comprehensive view of updating the
library, since they can provide new versions of headers, DLLs, and
all in one SP.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com


David Wilkinson

2006-03-13, 7:58 am

Thanks for the reply. Inline:

P.J. Plauger wrote:

>
>
> Well, it does save link time and code size in .exe files.


Yes, but as always with dynamic linking, this is no real advantage if I
have to ship the DLL's myself. Is the real reason not what I say (same
as it is for MFC with extension DLL's)?

>


> Dunno. I'd like to think so.
>


But don't you write these library headers? Is it just a matter of
removing all the "#ifdef _DLL" sections? What I would like (if I used
dynamic linking) would be a preprocessor symbol that I could define that
would remove the "extern" declarations, something like:

#if defined _DLL and !defined _NO_EXTERN

Would this not be possible? Or is there more to it than this?

>
>
> I think Microsoft takes a more comprehensive view of updating the
> library, since they can provide new versions of headers, DLLs, and
> all in one SP.


Yes, but in VC6 we had 6 service packs none of which, for whatever
reason, included the patches. And in VC7/7.1/8 we so far have none.

David Wilkinson

P.J. Plauger

2006-03-13, 7:58 am

"David Wilkinson" <no-reply@effisols.com> wrote in message
news:eAgSNGpRGHA.5468@TK2MSFTNGP14.phx.gbl...

> Thanks for the reply. Inline:
>
> P.J. Plauger wrote:
>
>
> Yes, but as always with dynamic linking, this is no real advantage if I
> have to ship the DLL's myself. Is the real reason not what I say (same as
> it is for MFC with extension DLL's)?


From what I see, DLLs *cause* the problem of passing objects across
DLL boundaries. But maybe I'm missing some other point you're making.

>
>
> But don't you write these library headers?


Yes. Then Microsoft works 'em over and we decide how much of their
changes to fold back into our baseline for our own products.

> Is it just a matter of removing
> all the "#ifdef _DLL" sections?


You don't have to do that. It's a matter of defining the appropriate
guiding macro definitions when you build. These either build for
DLLs or for a static library.

> What I would like (if I used
> dynamic linking) would be a preprocessor symbol that I could define that
> would remove the "extern" declarations, something like:
>
> #if defined _DLL and !defined _NO_EXTERN
>
> Would this not be possible? Or is there more to it than this?


It's already there (see _BUILD), but that's not the whole story.
We can't seem to build certain libraries static because of conflicts
with the underlying libraries we have to use. Typically, there's one
magic runtime function we have to use as-is and another that we have
to replace, and both are packaged in the same module. Similarly,
we *have* to build other libraries static whether we want to or not.

>
> Yes, but in VC6 we had 6 service packs none of which, for whatever reason,
> included the patches. And in VC7/7.1/8 we so far have none.


I can't comment on Microsoft's support decisions. It's their business
how they do it. We're the back room guys.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com


David Wilkinson

2006-03-13, 7:02 pm

P.J. Plauger wrote:

> "David Wilkinson" <no-reply@effisols.com> wrote in message
> news:eAgSNGpRGHA.5468@TK2MSFTNGP14.phx.gbl...
>
>
>
>
> From what I see, DLLs *cause* the problem of passing objects across
> DLL boundaries. But maybe I'm missing some other point you're making.
>
>
>
>
> Yes. Then Microsoft works 'em over and we decide how much of their
> changes to fold back into our baseline for our own products.
>
>
>
>
> You don't have to do that. It's a matter of defining the appropriate
> guiding macro definitions when you build. These either build for
> DLLs or for a static library.
>
>
>
>
> It's already there (see _BUILD), but that's not the whole story.
> We can't seem to build certain libraries static because of conflicts
> with the underlying libraries we have to use. Typically, there's one
> magic runtime function we have to use as-is and another that we have
> to replace, and both are packaged in the same module. Similarly,
> we *have* to build other libraries static whether we want to or not.
>
>
>
>
> I can't comment on Microsoft's support decisions. It's their business
> how they do it. We're the back room guys.
>
> P.J. Plauger
> Dinkumware, Ltd.
> http://www.dinkumware.com
>
>


PJ:

I don't see this _BUILD preprocessor symbol in the Standard Library
files for VC6 or VC7. Is this a VC8 thing?

As you say, Pete Becker is the expert. But what I mean is: Suppose my
application consists of a .exe and one or more DLL's. Then if I want to
pass std::string objects between two modules, then both these modules
had better be using the same heap. If either is statically linked to
CRT, they won't be. So you are forced to either NOT pass std::string
objects across the boundary (my choice) or link everything dynamically
to CRT. In the latter case, I think I have to use (and ship) msvcp60.dll
(or later version), though I'm not sure why. I just don't see why this
is necessary. If my two modules are using the same CRT heap anyway, why
do I need msvcp60.dll ?

Of course for me this is all academic because I always static link
everything. But most people do not.

David Wilkinson
Stephen Howe

2006-03-13, 7:02 pm

> I don't see this _BUILD preprocessor symbol in the Standard Library
> files for VC6 or VC7. Is this a VC8 thing?
>
> As you say, Pete Becker is the expert. But what I mean is: Suppose my
> application consists of a .exe and one or more DLL's. Then if I want to
> pass std::string objects between two modules, then both these modules
> had better be using the same heap. If either is statically linked to
> CRT, they won't be. So you are forced to either NOT pass std::string
> objects across the boundary (my choice) or link everything dynamically
> to CRT.


All correct so far.
You can pass std::string and not use CRT in DLL form but it is effectively
read-only.
And it is not just the heap, it is any static data that the C or C++
libraries use.
So fopen() in an EXE and fclose() in a DLL may cause problems.

> In the latter case, I think I have to use (and ship) msvcp60.dll
> (or later version), though I'm not sure why. I just don't see why this
> is necessary. If my two modules are using the same CRT heap anyway, why
> do I need msvcp60.dll ?


msvcp60.dll is the C++ RTL functions, _NOT_ the C RTL functions in DLL form.
If you statically link, I am not sure you should get this dependency.

Stephen Howe


David Wilkinson

2006-03-13, 7:02 pm

Stephen Howe wrote:

>
>
> All correct so far.
> You can pass std::string and not use CRT in DLL form but it is effectively
> read-only.
> And it is not just the heap, it is any static data that the C or C++
> libraries use.
> So fopen() in an EXE and fclose() in a DLL may cause problems.
>
>
>
>
> msvcp60.dll is the C++ RTL functions, _NOT_ the C RTL functions in DLL form.
> If you statically link, I am not sure you should get this dependency.
>
> Stephen Howe
>
>


Stephen:

Thanks for the reply. But what is the C++ RTL? And why does std::string
have to be compiled into it?

David Wilkinson
Stephen Howe

2006-03-13, 7:02 pm

> Stephen:
>
> Thanks for the reply. But what is the C++ RTL?


It is cin cout, cerr, wcin, ostream, istream, fstream, ostringstream,
istringstream, streambuf, locale, facets etc, member functions etc. You can
see all the exports by opening MSVCP60.DLL with DEPENDS.EXE
2104 exported functions.

Bear in mind that VC6.0 comes with 2 C++ libraries: a legacy C++ library
(Microsofts) and new C++ library closer to ISO C++ standard (Dinkumware's).
The former uses .H include files, the latter uses extensionless include
files. Don't mix the 2 C++ libraries :-)

For VC++ 6.0 you have

Single-threaded
==========
LIBC.LIB - single-threaded standalone C library, release
LIBP.LIB - single-threaded standalone C++ library (new),
release
LIBI.LIB - single-threaded standalone C++ library
(legacy), release

LIBCD.LIB - single-threaded C library, debug
LIBPD.LIB - single-threaded standalone C++ library (new),
debug
LIBID.LIB - single-threaded standalone C++ library
(legacy), debug

Compile options /ML and /MLd select these

Multi-threaded
==========
LIBCMT.LIB - multi-threaded standalone C library, release
LIBPMT.LIB - multi-threaded standalone C++ library (new),
release
LIBIMT.LIB - multi-threaded standalone C++ library
(legacy), release

LIBCMTD.LIB - multi-threaded C library, debug
LIBPMTD.LIB - multi-threaded standalone C++ library (new),
debug
LIBIMTD.LIB - multi-threaded standalone C++ library
(legacy), debug

Compile options /MT and /MTd select these

Multi-threaded in DLL form (no single-threaded exists)
=====================================
MSVCRT.LIB - multi-threaded export stubs for C library as
DLL, release
MSVCPRT.LIB - multi-threaded export stubs for C++ library
(new) as DLL, release
MSVCIRT.LIB - multi-threaded export stubs for C++ library
(legacy) as DLL, release

MSVCRTD.LIB - multi-threaded export stubs for C library as
DLL, debug
MSVCPRTD.LIB - multi-threaded export stubs for C++ library
(new) as DLL, debug
MSVCIRTD.LIB - multi-threaded export stubs for C++ library
(legacy) as DLL, debug

For these above, the corresponding RTL DLLs are

MSVCRT.DLL - multi-threaded C RTL in DLL form, release
MSVCP60.DLL - multi-threaded C++ RTL in DLL form (new), release
MSVCIRT.DLL - multi-threaded C++ RTL in DLL form (legacy), release

MSVCRTD.DLL - multi-threaded C RTL in DLL form, debug
MSVCP60D.DLL - multi-threaded C++ RTL in DLL form (new), debug
MSVCIRTD.DLL - multi-threaded C++ RTL in DLL form (legacy), debug

Compile options /MD and /MDd select these

> And why does std::string
> have to be compiled into it?


Must be your compiler options. They are not set right for some modules.
Somewhere you are compiling with /MD or /MDd set
If you consistently compile with /ML or /MT (and debug versions) for all
modules, you should not have any dependencies on MSVCP60.DLL.

Notes for V Studio 2001 and greater, the legacy C++ libraries have been
removed as an option.

Stephen Howe



David Wilkinson

2006-03-13, 7:02 pm

Stephen Howe wrote:

>
>
> It is cin cout, cerr, wcin, ostream, istream, fstream, ostringstream,
> istringstream, streambuf, locale, facets etc, member functions etc. You can
> see all the exports by opening MSVCP60.DLL with DEPENDS.EXE
> 2104 exported functions.
>
> Bear in mind that VC6.0 comes with 2 C++ libraries: a legacy C++ library
> (Microsofts) and new C++ library closer to ISO C++ standard (Dinkumware's).
> The former uses .H include files, the latter uses extensionless include
> files. Don't mix the 2 C++ libraries :-)
>
> For VC++ 6.0 you have
>
> Single-threaded
> ==========
> LIBC.LIB - single-threaded standalone C library, release
> LIBP.LIB - single-threaded standalone C++ library (new),
> release
> LIBI.LIB - single-threaded standalone C++ library
> (legacy), release
>
> LIBCD.LIB - single-threaded C library, debug
> LIBPD.LIB - single-threaded standalone C++ library (new),
> debug
> LIBID.LIB - single-threaded standalone C++ library
> (legacy), debug
>
> Compile options /ML and /MLd select these
>
> Multi-threaded
> ==========
> LIBCMT.LIB - multi-threaded standalone C library, release
> LIBPMT.LIB - multi-threaded standalone C++ library (new),
> release
> LIBIMT.LIB - multi-threaded standalone C++ library
> (legacy), release
>
> LIBCMTD.LIB - multi-threaded C library, debug
> LIBPMTD.LIB - multi-threaded standalone C++ library (new),
> debug
> LIBIMTD.LIB - multi-threaded standalone C++ library
> (legacy), debug
>
> Compile options /MT and /MTd select these
>
> Multi-threaded in DLL form (no single-threaded exists)
> =====================================
> MSVCRT.LIB - multi-threaded export stubs for C library as
> DLL, release
> MSVCPRT.LIB - multi-threaded export stubs for C++ library
> (new) as DLL, release
> MSVCIRT.LIB - multi-threaded export stubs for C++ library
> (legacy) as DLL, release
>
> MSVCRTD.LIB - multi-threaded export stubs for C library as
> DLL, debug
> MSVCPRTD.LIB - multi-threaded export stubs for C++ library
> (new) as DLL, debug
> MSVCIRTD.LIB - multi-threaded export stubs for C++ library
> (legacy) as DLL, debug
>
> For these above, the corresponding RTL DLLs are
>
> MSVCRT.DLL - multi-threaded C RTL in DLL form, release
> MSVCP60.DLL - multi-threaded C++ RTL in DLL form (new), release
> MSVCIRT.DLL - multi-threaded C++ RTL in DLL form (legacy), release
>
> MSVCRTD.DLL - multi-threaded C RTL in DLL form, debug
> MSVCP60D.DLL - multi-threaded C++ RTL in DLL form (new), debug
> MSVCIRTD.DLL - multi-threaded C++ RTL in DLL form (legacy), debug
>
> Compile options /MD and /MDd select these
>
>
>
>
> Must be your compiler options. They are not set right for some modules.
> Somewhere you are compiling with /MD or /MDd set
> If you consistently compile with /ML or /MT (and debug versions) for all
> modules, you should not have any dependencies on MSVCP60.DLL.
>
> Notes for V Studio 2001 and greater, the legacy C++ libraries have been
> removed as an option.
>
> Stephen Howe
>


Stephen:

Thanks again. Actually, I do not have any problems, because I always
static link (MT).

I had somehow thought that the whole of the standard library was in
header files. but I guess it isn't, and that if I do dynamic linking and
use any part of the (new) standard library, then I will need to link to
MSVCP60.DLL.

But I still do not understand why std::string, which IS completely
implemented in header files, is compiled into MSVCP60.DLL. It just seems
to cause a lot of trouble. Again, I use static linking, so it doesn't
bother me.

<aside>
When I first tried dynamic linking years ago, I was using the old
iostream library, so it was MSVCIRT.DLL that I needed. That is why I
thought that the need for MSVCP60.DLL was caused by starting to use
std::string. I forgot that I switched to the new libraries and so needed
it anyway (if I wanted to dynamic link).
</aside>

David Wilkinson


Tom Widmer [VC++ MVP]

2006-03-14, 7:58 am

David Wilkinson wrote:

> But I still do not understand why std::string, which IS completely
> implemented in header files, is compiled into MSVCP60.DLL. It just seems
> to cause a lot of trouble. Again, I use static linking, so it doesn't
> bother me.


Unlike std::vector and the other containers/algorithms/etc.,
std::basic_string only has two commonly used specializations, at least
one of which (std::string) is used internally by the iostreams
implementation. So, given that the iostreams stuff is included in the
DLL, why not also export string and wstring, to slightly reduce compile
time, exe size and program memory usage (due to not having multiple
copies of the string's code in memory at once)?

Tom
David Wilkinson

2006-03-14, 7:03 pm

Tom Widmer [VC++ MVP] wrote:

> David Wilkinson wrote:
>
>
>
> Unlike std::vector and the other containers/algorithms/etc.,
> std::basic_string only has two commonly used specializations, at least
> one of which (std::string) is used internally by the iostreams
> implementation. So, given that the iostreams stuff is included in the
> DLL, why not also export string and wstring, to slightly reduce compile
> time, exe size and program memory usage (due to not having multiple
> copies of the string's code in memory at once)?
>
> Tom


Tom;

Because it makes it impossible to patch std::string without rebuilding
MSVCP60.DLL (if you use static linking). The patches for <string> and
<xstring> were available at Dinkumware for many years, but never made
into any of the 6 VC6 service packs. To this day, the getline bug
remains in dynamically linked VC6 (SP6). For static linking, you just
patch the headers.

I'm sure it is partly the old legal problem, but I think MS is very
unwilling to create multiple versions of the C++ RTL DLL's, because they
already have enough trouble with the C RTL and MFC DLL's. And of course,
in C++, if you change the layout of a class in the DLL, you will break
existing code.

So, I say put as little as possible into the C++ RTL DLL's.

I'm still not sure why there has to be such a DLL at all. Since most of
the standard library is defined in header files, why isn't all of it? In
fact, I thought that if you purchased Dinkumware's C++ upgrade library
(or switched to STLPORT), all you had to do is change the include path.
I think I'm still missing something.

David Wilkinson
Tom Widmer [VC++ MVP]

2006-03-14, 7:03 pm

David Wilkinson wrote:
> Tom Widmer [VC++ MVP] wrote:
>
>
>
> Tom;
>
> Because it makes it impossible to patch std::string without rebuilding
> MSVCP60.DLL (if you use static linking).


My question was rhetorical. At the time the decision was made to include
string in the DLL, it obviously wasn't known that it either had any bugs
in or that there would be a problem with patching the DLL in an SP,
which is obviously the normal way that library bugs are handled.

The patches for <string> and
> <xstring> were available at Dinkumware for many years, but never made
> into any of the 6 VC6 service packs. To this day, the getline bug
> remains in dynamically linked VC6 (SP6). For static linking, you just
> patch the headers.
>
> I'm sure it is partly the old legal problem, but I think MS is very
> unwilling to create multiple versions of the C++ RTL DLL's, because they
> already have enough trouble with the C RTL and MFC DLL's. And of course,
> in C++, if you change the layout of a class in the DLL, you will break
> existing code.


I think they are trying to improve matters with the new shared
side-by-side assembly stuff. I believe this allows MS to fix the CRT
DLLs using Windows Update (with your application's permission, I assume).

> So, I say put as little as possible into the C++ RTL DLL's.


That just leads to code bloat. If you've got 10 CRT using DLLs, you'll
end up with 11 copies of std::string's code, etc.

> I'm still not sure why there has to be such a DLL at all. Since most of
> the standard library is defined in header files, why isn't all of it?


For the same reasons that other libraries aren't defined solely in
header files. To put non-template functions (or explicit specializations
of template functions) in header files, they must be declared inline,
which is going to cause serious bloat in many cases. The only reason
most of it is in header files is due to compiler limitations when it
comes to templates.

In
> fact, I thought that if you purchased Dinkumware's C++ upgrade library
> (or switched to STLPORT), all you had to do is change the include path.
> I think I'm still missing something.


Dinkumware's upgrade library involves new binaries I believe. STLport
also has dll and lib files, though only if you want to use STLport's
IOstreams.

The iostreams component is really quite big, and almost all of it is
brought into any statically CRT linking project that does any std IO, so
basically you are adding the much of the size of the CRT DLL to every
..exe and DLL that statically links to the CRT. Not to mention the shared
heap as well, which can be useful if you want to pass ownership of
memory across the DLL boundary.

If you don't use DLLs, then the only advantage of dynamically linking to
the CRT is the side-by-side assembly stuff I mentioned above.

Tom
Stephen Howe

2006-03-14, 7:03 pm

> I had somehow thought that the whole of the standard library was in
> header files. but I guess it isn't, and that if I do dynamic linking and
> use any part of the (new) standard library, then I will need to link to
> MSVCP60.DLL.


Here at work we are using VC++ 2003.
We should be shortly switching to VC++ 2005.
I have looked round the office to see if we have any PC's left with Visual
C++ 6.0 installed (there is one machine and I will find out tomorrow). More
on this below.

I am baffled by what you say, but I think the intention (even if the reality
is not so) is that if you compile stand alone, you should not get
dependencies to any of MSVCRT.DLL, MSVCP60.DLL or MSVCIRT.DLL.

Now I know there were a few flaws in the header files for Visual Studio
5.0/6.0.
And further these were fixed by downloading header files from Dinkumware.
The implications of that is that is anything inline is fixed.

> But I still do not understand why std::string, which IS completely
> implemented in header files, is compiled into MSVCP60.DLL.


Why? You are thinking from the compiler point-of-view not the linker's
point-of-view.

If you do

#include <string>

unsigned foobar()
{ std::string test("Here I am");
return test.size();
}[color=darkred]

then a call to the constructor for std::string and destructor will be
inserted into the code of foobar.
That is an actual function call. And that will be expanded from the
definition of std:string in <string>.
But where does that constructor for std::string actually live? Where does it
reside? The body of the code?
Well if you compiled with /MD in force, the constructor, I think, lives
inside MSVCP60.DLL.
If you compiled with /ML or /MT in force, the constructor I think, lives
inside LIBP.LIB or LIBPMT.LIB and is linked in. I say "I think" because I
have not checked this. A linker MAP file would confirm/deny this. In any
case, you will find that some template functions are instantiated in your
OBJ file but some are not and are pulled out from LIB files or a call to DLL
is generated.

Do you have DEPENDS? You should have.
I don't have Visual C++ 6.0 on hand but I have Visual C++ 7.1 and results
are similar.
If I have the test code
[color=darkred]
#include <iostream>
#include <string>
int main()
{
std::string hw("hello world");
std::cout << hw << std::endl;
return 0;
}[color=darkred]

and I do (using command line compiler)

1. Compile with

CL /GX /O2 /ML /Fm TEST.CPP
and run UNDNAME on TEST.MAP

then if I view the executable using DEPENDS there are no run-time C or C++
DLL dependencies (apart from KERNEL32.DLL & NTDLL.DLL). If I look at the map
file, I see (this is condensed, just to make my point)
[color=darkred]
0001:00000000 public: void __thiscall std::basic_ios<char,struct
std::char_traits<char> >::clear(int,bool) 00401000 f i TEST.obj
0001:00000020 protected: void __thiscall
std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> >::_Eos(unsigned int) 00401020 f i TEST.obj
0001:000003f0 class std::basic_ostream<char,struct
std::char_traits<char> > & __cdecl 0001:00000b49 public: void
__thiscall std::ios_base::_Addstd(void) 00401b49 f libcp:ios.obj
0001:00000b7f private: void __thiscall std::ios_base::_Tidy(void)
00401b7f f libcp:ios.obj
0001:00000bc1 public: virtual __thiscall
std::ios_base::~ios_base(void) 00401bc1 f libcp:ios.obj
[color=darkred]

What this shows is that string::_Eos (an implementation function) has been
emitted into TEST.OBJ. An examples of instantiantion.
But ios_base::Tidy() (another implementation function) lives in IOS.OBJ and
comes from LIBCP.LIB. It has not been instantianted.

2. Compile with

CL /GX /O2 /MD /Fm TEST.CPP
and run UNDNAME on TEST.MAP

Now if I view using DEPENDS, I see

MSVCP71.DLL (7.1 C RTL in DLL form)
MSVCR71.DLL (7.1 C++ RTL in DLL form)
and the other 2 Windows DLLs

If I examine the imports from MSVCP71.DLL that TEST.EXE has made, I see
[color=darkred]
void std::_Mutex::_Lock(void)
void std::_Mutex::_Unlock(void)
void std::basic_ostream<char,struct std::char_traits<char> >::_Osfx(void)
class std::basic_ostream<char,struct std::char_traits<char> > &
std::basic_ostream<char,struct std::char_traits<char> >::flush(void)
class std::basic_ostream<char,struct std::char_traits<char> > &
std::basic_ostream<char,struct std::char_traits<char> >::operator<<(class
std::basic_ostream<char,struct std::char_traits<char> > & (*)(class
std::basic_ostream<char,struct std::char_traits<char> > &))
int std::basic_streambuf<char,struct std::char_traits<char> >::sputc(char)
std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> >::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >(char const *)
std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> >::~basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >(void)
class std::basic_ostream<char,struct std::char_traits<char> > std::cout
class std::basic_ostream<char,struct std::char_traits<char> > &
std::endl(class std::basic_ostream<char,struct std::char_traits<char> > &)
void std::ios_base::clear(int,bool)
bool std::uncaught_exception(void)[color=dark
red]

and that is it. If I examine TEST.MAP file I see (again cut down)
[color=darkred]
0001:00000000 public: __thiscall std::basic_ostream<char,struct
std::char_traits<char> >::_Sentry_base::~_Sentry_base(void) 00401000 f i
TEST.obj
0001:00000020 public: __thiscall std::basic_ostream<char,struct
std::char_traits<char> >::sentry::sentry(class
std::basic_ostream<char,struct std::char_traits<char> > &) 00401020 f i
TEST.obj
0001:000000b0 public: __thiscall std::basic_ostream<char,struct
std::char_traits<char> >::sentry::~sentry(void) 004010b0 f i TEST.obj
0001:00000320 _main 00401320 f TEST.obj
0001:00000394 ___CxxFrameHandler 00401394 f
MSVCRT:MSVCR71.dll
0001:000003a0 _mainCRTStartup 004013a0 f
MSVCRT:crtexe.obj
0001:00000538 __XcptFilter 00401538 f
MSVCRT:MSVCR71.dll
0001:0000053e __amsg_exit 0040153e f
MSVCRT:MSVCR71.dll
0001:00000544 __onexit 00401544 f
MSVCRT:atonexit.obj
0001:0000056a _atexit 0040156a f
MSVCRT:atonexit.obj
0002:00000000 __imp__GetModuleHandleA@4 00402000
kernel32:KERNEL32.dll
0002:00000004 \177KERNEL32_NULL_THUNK_DATA 00402004
kernel32:KERNEL32.dll
0002:00000008 __imp_public: __thiscall std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char>[color=darkred]
>::~basic_string<char,struct std::char_traits<char>,class

std::allocator<char> >(void) 00402008 msvcprt:MSVCP71.dll
0002:0000000c __imp_public: __thiscall std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char>
>::basic_string<char,struct std::char_traits<char>,class

std::allocator<char> >(char const *) 0040200c msvcprt:MSVCP71.dll[color=darkred]

and you can see that some template functions have been instantiated into
TEST.OBJ, some imported from MSVCR71.DLL, some imported from MSVCP71.DLL (so
TEST.EXE will be making calls to these functions which live in the DLLs),
some imported from KERNEL32.DLL.

Returning back to Visual 6.0.
If you get dependencies on MSVCP60.DLL despite compiling throughout with /ML
or /MT, then I think that is a Microsoft oversight (bug?). The intention was
that your standalone program should be self-sufficient, not dependent on any
DLL (apart from Windows OS ones) if compiled with /ML or /MT. It might be an
idea to try the code above with VC++ 6.0, run it though DEPENDS and find out
exactly what is being imported from MSVCP60.DLL.

Cheers

Stephen Howe


Stephen Howe

2006-03-14, 7:03 pm

> The only reason
> most of it is in header files is due to compiler limitations when it
> comes to templates.


By that, do you mean export is not implemented?

Thanks

Stephen Howe


Tom Widmer [VC++ MVP]

2006-03-15, 7:58 am

Stephen Howe wrote:
>
>
> By that, do you mean export is not implemented?


Basically, yes. I also mean the general limitation of templates where
the definition is dependent on the usage. In any case, existing
implementations of export aren't all that much better than just using
headers (though this may change with a new version of the EDG front end
- perhaps we'll see some kind of template "object" file).

Tom
David Wilkinson

2006-03-15, 7:02 pm

Stephen Howe wrote:

>
>
> Here at work we are using VC++ 2003.
> We should be shortly switching to VC++ 2005.
> I have looked round the office to see if we have any PC's left with Visual
> C++ 6.0 installed (there is one machine and I will find out tomorrow). More
> on this below.
>
> I am baffled by what you say, but I think the intention (even if the reality
> is not so) is that if you compile stand alone, you should not get
> dependencies to any of MSVCRT.DLL, MSVCP60.DLL or MSVCIRT.DLL.
>
> Now I know there were a few flaws in the header files for Visual Studio
> 5.0/6.0.
> And further these were fixed by downloading header files from Dinkumware.
> The implications of that is that is anything inline is fixed.
>
>
>
>
> Why? You are thinking from the compiler point-of-view not the linker's
> point-of-view.
>
> If you do
>
>
> #include <string>
>
> unsigned foobar()
> { std::string test("Here I am");
> return test.size();
> }
>
>
> then a call to the constructor for std::string and destructor will be
> inserted into the code of foobar.
> That is an actual function call. And that will be expanded from the
> definition of std:string in <string>.
> But where does that constructor for std::string actually live? Where does it
> reside? The body of the code?
> Well if you compiled with /MD in force, the constructor, I think, lives
> inside MSVCP60.DLL.
> If you compiled with /ML or /MT in force, the constructor I think, lives
> inside LIBP.LIB or LIBPMT.LIB and is linked in. I say "I think" because I
> have not checked this. A linker MAP file would confirm/deny this. In any
> case, you will find that some template functions are instantiated in your
> OBJ file but some are not and are pulled out from LIB files or a call to DLL
> is generated.
>

[snip]
>
> Returning back to Visual 6.0.
> If you get dependencies on MSVCP60.DLL despite compiling throughout with /ML
> or /MT, then I think that is a Microsoft oversight (bug?). The intention was
> that your standalone program should be self-sufficient, not dependent on any
> DLL (apart from Windows OS ones) if compiled with /ML or /MT. It might be an
> idea to try the code above with VC++ 6.0, run it though DEPENDS and find out
> exactly what is being imported from MSVCP60.DLL.
>
> Cheers
>
> Stephen Howe
>


Stephen:

Thanks again for the reply.

I think you misunderstand me. I always use static linking and do not
have any need for MSVCP60.DLL. I applied the Dinkumware patches and they
worked without rebuilding anything (except my code of course).

What I am concerned about is that even after 6 service packs, the last
surely after the legal issues were resolved, these patches did not make
their way into MSVCP60.DLL. So that if I did want to use dynamic
linking, the VC6 standard library would be defective. I know there is at
least one defect in the VC7.1 standard library, and we know how many
service packs there have been for that.

std::string is based on a templated class, so (export lacking) I would
normally expect it to be inlined into my program. But as Tom pointed
out, there are only two common instantiations of much of the standard
library, i.e. those for char and wchar_t, and MS has chosen to compile
those into the C++ RTL DLL. Unfortunately, IMHO, but they did.

It seems that there must be things that are compiled into MSVCP60.DLL
that are not compiled into LIBP.LIB or LIBPMT.LIB (otherwise the patches
would not take effect), and I am not sure why this is. I will try to
find time to play around with DEPENDS and find out what is where.

But for now I remain a happy static linker...

David Wilkinson


Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com