Article ID: 138400
Article Last Modified on 5/31/2005
Public Symbols for OBJ 1
Module 1 _____________________
_____________________________| _var1----------|------------------
| | _func1 | |
| var1 |___________________| |
| . | PST for OBJ 1 |
| . | |
| . | |
| func1 { |Required Symbols for OBJ 1 |
| func2( ); __|__________________ |
| var1 = 2; | _func2 |<<________ |
| var2 = 4; | _var2 |<<______ | |
| } |_____________________| | | |
| | UST for OBJ 1 | | |
|________________________________| | | |
| | |
| | |
| | |
Public Symbols for OBJ 2 | | |
Module 2 _____________________ | | |
_____________________________| _var2----------|---------| | |
| | _func2---------|-----------| |
| var2 |___________________| |
| . | PST for OBJ 2 |
| . | |
| . | |
| func2 { |Required Symbols for OBJ 2 |
| func3( ); __|__________________ |
| var1 = 3; | _var1 |_______________|
| var2 = 5; | _func3 |_______________
| } |_____________________| |
| | UST for OBJ 2 |
|________________________________| |
|
|
Unresolved External Error is issued
for _func3() because there is no
definition found for func3() in
the PST for either OBJ module.
The linker uses the PST and UST of a project's object and library files to
match symbol names. If the linker finds a symbol in a UST table and cannot
find a matching entry in one of the many PST tables, it issues an
"Unresolved External" error message. For example, in Figure 1, the linker
cannot resolve the address for the function func3() and therefore issues an
"Unresolved External" error.
31986 Maximum Number of Libraries LINK Supports
/* test.cpp */
void DoSomething(void);
void main(void){
DoSomething( ); // This line causes an unresolved external error
// because the prototype for DoSomething() allows the
// compiler to think the function exists. However,
// the linker finds that it doesn't.
}
When using C++, make sure you provide a function definition for each
function in a class and not just a prototype in the class definition. If
you are defining the function outside of the class definition, be sure to
include the class name before the function in the Classname::MemberFunction
style. See the "Scoping Problems and Pure Virtual Functions" section for an
example.
DUMPBIN /SYMBOLS <filename.obj>For libraries, use this command:
DUMPBIN /LINKERMEMBER[:{1|2}] <libraryname.lib>
For 16-bit libraries, use Lib.exe to view the symbols defined in the
library. To create a listing use this command:
LIB <filename.lib>, <filename.lst>If you want to determine what symbols are contained in an object module, create a dummy library and listing file from the object module with Lib.exe. For example:
LIB <dummy.lib> +<filename.obj>, <filename.lst>On Windows 95, you can use the QuickViewer to see some of this same information for .exe and .dll files.
void CALLTYPE test(void)might come to anything in the following table depending on what the CALLTYPE is and whether it is a C or a C++ file.
Calling convention extern "C" .CPP, .CXX, or .C file C naming convention (__cdecl) _test ?test@@YAXXZ Fastcall naming convention (__fastcall) @test@0 ?test@@YIXXZ Standard Call naming convention (__stdcall) _test@0 ?test@@YGXXZCALLTYPEs such as _cdecl, _fastcall, and _stdcall change the naming conventions for a function or variable. The 32-bit specific __declspec(<attribute>) modifier can also affect the name of the function.
// Test1.h
void _stdcall func( char, float );
// Test1.cpp
void _stdcall func( char a ){
a = 'a';
}
// Test.cpp
#include "test1.h"
void main(void) {
char var1;
float var2 = 5;
func ( var1, var2 ); // Unresolved external error occurs here
}
There is no set standard for naming conventions between compiler vendors or
even between different versions of a compiler. Therefore cross-linking
object files compiled with other compilers or compiler versions may cause
unresolved externals.
/* main.cpp */
extern void func1(void);
void main(void) {
func1(); // Unresolved external occurs because func1() is a
// static function in the file test.cpp.
}
/* test.cpp */
static void func1(void) {
//Do something
}
Automatic (function scope) variables:
/* main.cpp */
void test(void);
static int lnktest3 = 3;
int lnktest4 = 4;
void main() {
static int lnktest1 = 1;
int lnktest2 = 2;
test();
}
/* test.cpp */
extern int lnktest1;
extern int lnktest2;
extern int lnktest3;
extern int lnktest4;
void test(void)
{
int i =0;
i = lnktest1; //causes unresolved external, reason 6-2
i = lnktest2; //causes unresolved external, reason 6-2
i = lnktest3; //causes unresolved external, reason 6-1
i = lnktest4; // OK
}
Global Constants in C++:
/* main.cpp */
void test(void);
const int lnktest1 = 0;
void main(void) {
test( );
}
/* test.cpp */
extern int lnktest1;
void test(void) {
int i = lnktest1; // Causes unresolved external, reason 6-3
}
One alternative is to include the const initializations in a header file,
and include that header in your C++ files when necessary, just as if it was
a function prototype. Another possibility is to make the variable non-
constant and use a const reference when accessing it.
/* test.cpp */
class A {
public:
F(void); // No implementation here.
void PublicStatMemFunc1(void) {
F( ); // This implicitly calls A::F because it's
} // inside a class member function declaration.
// May have forgotten to implement A::F() or meant
// to call ::F( )
};
void F(void) { //Maybe meant to be the implementation of A::F( ) ?
}
void main(void) {
A testclsObject;
testclsObject.PublicStatMemFunc1( ); //This code needed for compiler
// to add entry to UST and
// generate unresolved external.
}
This case could be wrong in one of two ways. The function call in
PublicStatMemFunc1() should have the scope resolution operator (::) added
to make a call to ::F(). The compiler will then know that the user meant to
call a global function. Alternatively, if the user meant F() to be the
class implementation of F(), the definition needs to be changed to A::F().
/* test.cpp */
class testcls {
public:
virtual void DoSomething(void)=0; // Makes this a virtual base class
testcls::testcls( ) {
DoSomething( );
}
};
class testcls2: public testcls {
public:
virtual void DoSomething(void) {} ;
};
void main(void) {
testcls2 testclsObject; // Needs to be here for error to occur
// since it forces the compiler to call
// the constructor for testcls.
}
/* Compile Options Needed: /Ob1 or /Ob2 */
/* testcls.h */
class testcls {
public:
void PublicFunc(void);
};
/* clasfunc.cpp */
#include "testcls.h"
inline void testcls::PublicFunc(void) {}
void DummyFunc(void) {
testcls TestClass;
TestClass.PublicFunc();
}
/* test2.cpp */
#include "testcls.h"
void main(void) {
testcls testclsObject;
testclsObject.PublicFunc( );
// This adds the entry to UST and causes an
// unresolved external because this module can not
} // see the implementation of PublicFunc( );
For more information on inline functions and unresolved externals, please
see the following article in the Microsoft Knowledge Base:
123768 Unresolved Externals for Inline Functions
Compile option Run-time usage Link with
--------------------------------------------------------
/ML (default) Single threaded static
run-time library Libc.lib
/MT Multithread run-time
library Libcmt.lib
/MD Multithread using DLL Msvcrt.lib
/LD Changes the default run-time library support
to /MT if you have not explicitly specified
/MD, /ML, or /MT.
Msvcrt.lib will link with a different version of the run time depending on
the version of Visual C++ that you are using. For version 2.x, the DLL is
Msvcrt20.dll. Also, note that with Visual C++ version 2.x, there are two
versions of Msvcrt20.dll -- one that targets Windows NT and Windows 95 and
one that targets Win32s. For more information on these DLLs, please see the
following article in the Microsoft Knowledge Base:
125476 PRB Error "...MSVCRT20.DLL is not compatible with Win32s"
/* Test.c */
/* Compile Options: /MD /c */
/* Link Options: /NOD:msvcrt.lib libcmt.lib */
#include <stdio.h>
void main(void) {
printf("hello"); // Generates unresolved external on __imp__printf
}
Keywords: kbprb KB138400