Re: Problem with reading an int with operator>>

Tech Tip: Click here to run a free scan for Windows Errors and optimize PC performance



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();
}


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


#include <iostream>
#include <string>
int main()
{
std::string hw("hello world");
std::cout << hw << std::endl;
return 0;
}


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)


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



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


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)


and that is it. If I examine TEST.MAP file I see (again cut down)


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>
::~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


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


.



Relevant Pages

  • Header files
    ... In the fortran code that I have, there is a subroutine in which ... I am using a pgi compiler to compile 2D.F and my code. ... character...and it gives the names of all header files. ...
    (comp.lang.fortran)
  • Re: Problem with reading an int with operator>>
    ... Stephen Howe wrote: ... Now I know there were a few flaws in the header files for Visual Studio ... So that if I did want to use dynamic linking, the VC6 standard library would be defective. ... 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. ...
    (microsoft.public.vc.stl)
  • Re: Print error alerts
    ... I tried to compile the code, ... I Ran you command: vbc ... 'Imports' statements must precede any declarations. ...
    (microsoft.public.backoffice.smallbiz2000)
  • Re: Another question on VS2003 to VS2005
    ... EVERY instance of the word "PASCAL" from the Platform SDK, MFC, and other header files. ... One thing you can do is add the /P switch to the compile line for this file (that's ... Check if LONG, GSFAR, GSPASCAL and GSEXPORT are correctly defined as something ... a class definition in a header file that is included before these lines. ...
    (microsoft.public.vc.mfc)
  • Re: changing module files
    ... > actually defined somewhere is not determined until compile time. ... methods, they must be defined in the declaration used by callers, ... > understand and be comfortable with all of the preprocessor macros. ... No macros are needed by C or C++ header files particularly except ...
    (comp.lang.fortran)