??xml version="1.0" encoding="utf-8" standalone="yes"?> ~译环境 VC6.0
--------------------Configuration: HY Messaging Server - Win32 Debug-------------------- Global.obj - 1 error(s), 0 warning(s) 1、安装Windows Platform February SDK 2003 2、STLPORT路径正确 3、正的配置下面的Directroy
2、当使用自己的库源文Ӟ如果功能使用了MFC支持Q库文g没有加入#include <afx.h>也发生了q个问题?br>3、需要打补丁SP5/6来解册个bug.
Compiling...
Global.cpp
c:\program files\microsoft visual studio\vc98\mfc\include\afx.h(556) : fatal error C1001: INTERNAL COMPILER ERROR
(compiler file 'msc1.cpp', line 1786)
Please choose the Technical Support command on the Visual C++
Help menu, or open the Technical Support help file for more information
Error executing cl.exe.
]]>
]]>
W号文gQ?span lang="EN-US">Symbol FilesQ是一个数据信息文Ӟ它包含了应用E序二进制文Ӟ比如Q?span lang="EN-US">EXE?span lang="EN-US">DLL{)调试信息Q专门用来作调试之用Q最l生成的可执行文件在q行时ƈ不需要这个符hӞ但你的程序中所有的变量信息都记录在q个文g中。所以调试应用程序时Q这个文件是非常重要的。用 Visual C++ ?span lang="EN-US"> WinDbg 调试E序旉要用到这个文件?span lang="EN-US">
?span lang="EN-US"> Windows pȝ中,W号文g?span lang="EN-US"> .pdb 为扩展名Q比如:每个 Windows 操作pȝ下有一?span lang="EN-US"> GDI32.dll 文gQ编译器在编译该 DLL 的时候会产生一?span lang="EN-US"> GDI32.pdb 文gQ一旦你拥有了这?span lang="EN-US"> PDB 文gQ那么便可以用它来调试ƈ跟踪?span lang="EN-US"> GDI32.dll 内部。该文g和二q制文g的编译版本密切相养I比如修改?span lang="EN-US"> DLL 的输出函敎ͼ再编译该 DLLQ那么原先的 PDB 文gp时了Q不能再用老的 PDB 文g来做调试工作,而必M用最新的 PDB 文g版本?span lang="EN-US">
Visual C++ ~译代码后会?span lang="EN-US"> Debug 或?span lang="EN-US"> Release 目录下生成一?span lang="EN-US"> PDB 文g。一般情况下Q符h件包括以下的数据信息Q?span lang="EN-US">
二、如何得到和安装W号文g?
安装W号文g的注意事:
如果是手动安装符hӞ有一点很重要Q那是宿主机(Hostt ComputerQ上的符h件必M目标机器Q?span lang="EN-US">Target ComputerQ上?span lang="EN-US"> Windows 版本相匹配?span lang="EN-US">
q里所谓的宿主机指的是q行调试会话的机器,在典型的双系l调试会话环境中Q宿L可以是连接到目标机器的Q何机器。目标机器指的是发生软glg、系l服务、应用程序或操作pȝq行p|的机器。也x需要被调试的机器,它是调试会话x的焦炏V目标机器可以近在咫,也可以位于完全不同的地方。有时我们也目标机器称之ؓ—?/span>被调试者(debuggeeQ,那么与之对应Q宿L则可以称试者(debuggerQ?span lang="EN-US">
三、在 Visual C++ 使用W号文g的方?/span>
?span lang="EN-US"> Visual C++ 6.0 中的使用ҎQ?span lang="EN-US">
?span lang="EN-US"> Visual C++ .NET 2003 中的使用ҎQ?span lang="EN-US">
四、如何?span lang="EN-US"> Release 版本二进制文件对应的 PDB 文g?
?span lang="EN-US"> Visual C++ 6.0 中的ҎQ?span lang="EN-US">
?span lang="EN-US"> Visual C++ .NET 2003 中的ҎQ?span lang="EN-US">
五、关?span lang="EN-US"> Free BuildQ也U?span lang="EN-US"> Retail BuildQ和 Checked BuildQ也U?span lang="EN-US"> Debug BuildQ?/span>
每个Z NT 操作pȝ有两U不同的E序生成模式Q即Q?span lang="EN-US">
Free Build 生成的是最l用L本,针对生成的二q制文gq行了彻底的优化Q禁用了调试断言Qƈ剥离了调试信息。这样一来可执行程序文件更,加蝲更快Q用的内存也更?span lang="EN-US">
Checked Build 生成的是试和调试版本。它包含额外?span lang="EN-US"> Free Build 所没有的错误检查,参数验证和调试信息,Checked Build 有助于隔d跟踪可能D不可预见的行为的问题Q比如内存溢出,不正的讑֤配置。虽?span lang="EN-US"> Checked Build 提供了额外的保护Q但?span lang="EN-US"> Free Build 比较Q它需要更多的内存开销和磁盘空间。由于可执行E序包含W号调试信息Q调试时要执行附加的代码、参数检查和输出调试诊断信息Q从而导致性能下降?span lang="EN-US">
六、系l符h件的更新Ҏ
pȝW号文g?span lang="EN-US"> Windows 操作pȝ依赖的那几个重要?span lang="EN-US"> DLL/SYS 和可执行文g对应的符hӞ常见的比如:gdi32.dll?span lang="EN-US">Kernel32.dll?span lang="EN-US">Kerberos.dll?span lang="EN-US">psapi.dll?span lang="EN-US">user32.dll{,使用 WinDbg 调试Ӟ你就会发现系l符h?span lang="EN-US">(PDB)有多重要Q这些文仉与本地的 OS 密切相关Q比如,Windows 2000 打了SP补丁的话Q那么必L新系l符h件才能进行相兌试,原来的符h件与打补丁后的系l就会不匚wQ怎么办呢? 可以通过|络来更斎ͼ象下面这样在 WinDbg ?span lang="EN-US"> Symbols Path 里面输入路径Q?span lang="EN-US">
SRV*D:\Symbols\websymbols*http://msdl.microsoft.com/download/symbols
Q斜体部分是你在本地保存W号文g的\径)
如果你不是通过代理上网Q那么在你用 WinDbg 打开一个被调试E序后,输入 symchk 回RQ?span lang="EN-US">WinDbg ׃自动的连到微软的|站Ҏ你的机器的情冉|新的 PDB 文gQƈ它保存在上面斜体部分指定的本地路径里,q样你就可以保你的W号文g版本和你机器上的文g版本一致?span lang="EN-US">
如果你是通过代理上网那么你需要配|?span lang="EN-US"> IE 的连接设|。具体方法恕不赘a?span lang="EN-US">
e:\svn_now\3rdparty\microsoft\platform_sdk\2003_02_full-r2\include\winsock2.h(109) : error C2011: 'fd_set' : 'struct' type redefinition
e:\svn_now\3rdparty\microsoft\platform_sdk\2003_02_full-r2\include\winsock2.h(144) : warning C4005: 'FD_SET' : macro redefinition
e:\svn_now\3rdparty\microsoft\platform_sdk\2003_02_full-r2\include\winsock.h(88) : see previous definition of 'FD_SET'
e:\svn_now\3rdparty\microsoft\platform_sdk\2003_02_full-r2\include\winsock2.h(153) : error C2011: 'timeval' : 'struct' type redefinition
e:\svn_now\3rdparty\microsoft\platform_sdk\2003_02_full-r2\include\winsock2.h(209) : error C2011: 'hostent' : 'struct' type redefinition
e:\svn_now\3rdparty\microsoft\platform_sdk\2003_02_full-r2\include\winsock2.h(222) : error C2011: 'netent' : 'struct' type redefinition
e:\svn_now\3rdparty\microsoft\platform_sdk\2003_02_full-r2\include\winsock2.h(229) : error C2011: 'servent' : 'struct' type redefinition
e:\svn_now\3rdparty\microsoft\platform_sdk\2003_02_full-r2\include\winsock2.h(241) : error C2011: 'protoent' : 'struct' type redefinition
e:\svn_now\3rdparty\microsoft\platform_sdk\2003_02_full-r2\include\winsock2.h(397) : error C2011: 'sockaddr_in' : 'struct' type redefinition
e:\svn_now\3rdparty\microsoft\platform_sdk\2003_02_full-r2\include\winsock2.h(407) : error C2011: 'WSAData' : 'struct' type redefinition
.................................
q是׃<config-win32.h>文g中包含了
#include <windows.h>
#include <winsock2.h>
windows.h中又包含?span lang="EN-US"><winsock.h>D?span lang="EN-US">winsock2.h冲突Q解x法是?span lang="EN-US">include<windows.h>之前d?span lang="EN-US">:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
因ؓ用到?span lang="EN-US">winsock2.h 所以必d?span lang="EN-US">lib文g:ws2_32.lib
再次~译Q出现如下错?span lang="EN-US">:
mudp.c
this compiler appears to lack vararg macros which will cause a significant degradation in efficiency
e:\libtools\openvpn-
multi.c
this compiler appears to lack vararg macros which will cause a significant degradation in efficiency
e:\libtools\openvpn-2.0.9\lzo.h(32) : fatal error C1083: Cannot open include file: 'lzo1x.h': No such file or directory
ntlm.c
this compiler appears to lack vararg macros which will cause a significant degradation in efficiency
occ.c
this compiler appears to lack vararg macros which will cause a significant degradation in efficiency
e:\libtools\openvpn-2.0.9\lzo.h(32) : fatal error C1083: Cannot open include file: 'lzo1x.h': No such file or directory
openvpn.c
#ifdef USE_LZO
#ifdef LZO_HEADER_DIR
#include "lzo/lzoutil.h"
#include "lzo/lzo1x.h"
#else
#include "lzoutil.h"
#include "lzo1x.h"
#endif
因ؓopenvpn默认配置用到?span lang="EN-US">lzo压羃库,所以下?span lang="EN-US">lzo压羃?span lang="EN-US">:lzo-2.03,q且?span lang="EN-US">lzo-2.03包中?span lang="EN-US">include文g加入到工E中Q注意文件目录层ơ,我是额外定义?span lang="EN-US">lzo文g夹,头文g全部加入q去的,因此必须加上~译选项:LZO_HEADER_DIR
另额外编?span lang="EN-US">lzo lib:
?span lang="EN-US">lzo解压?span lang="EN-US">C盘根目录Q在命o行中跌该目录,q行b\win32\mc120.batQ编译成功后生成lzo.lib
生成的lzo.libd到工E中?span lang="EN-US">
另如果不是用lzo可以修改<config_win32.h>头文?span lang="EN-US">: (openssl ssl crypto也可以不使用Q视具体情况)
/* Use OpenSSL crypto library */
#define USE_CRYPTO 1
/* Use LZO compression library */
#define USE_LZO 1
/* Use OpenSSL SSL library */
#define USE_SSL 1
/* Version number of package */
#define VERSION PACKAGE_VERSION
接着如果使用OpenSSLQ那么首先要下蝲OpenSSL库,然后~译:
a.?span lang="EN-US">OpenSSL解压?span lang="EN-US">C盘根目录下;
b.在命令提C中进入该目录Q输?span lang="EN-US">perl Configure VC-WIN32Q检?span lang="EN-US">perl是否正确安装Q?span lang="EN-US">
c.命o行中输入ms\do_msQ?span lang="EN-US">
d.命o行中转到Microsoft Visual Studio\VC98\binQ运?span lang="EN-US">vcvars32.bat以配|环境变量?span lang="EN-US">
e.命o?span lang="EN-US">OpenSSL目录下,执行nmake –f ms\ntdll.mak ~译成功后,?span lang="EN-US">out32dll目录下,会有四个文glibeay32.dll libeay32.lib ssleay32.dll?span lang="EN-US"> ssleay32.lib,编译成功的lzo.lib libeay32.lib ssleay32.libd到工E中Qƈ?span lang="EN-US">libeay32.dll ssleay32.dll拯?span lang="EN-US">Debug目录?span lang="EN-US">,q且加入openssl的头文g到工E中Q和lzo库类似的q程?span lang="EN-US">
另外因ؓVC中不识别unsigned long long intcdQ需改ؓ_int64。修?span lang="EN-US"><common.h>头文?span lang="EN-US">:
#ifdef USE_64_BIT_COUNTERS
// typedef unsigned long long int counter_type;
typedef _int64 counter_type; //qj modify
# ifdef WIN32
# define counter_format "%I64u"
# else
# define counter_format "%llu"
# endif
#else
typedef unsigned int counter_type;
# define counter_format "%u"
#endif
再次~译Q发现错误少多了Q而且全部只是一?span lang="EN-US">link错误?span lang="EN-US">:
Linking
LINK : warning LNK4098: defaultlib "MSVCRT" conflicts with use of other libs; use /NODEFAULTLIB:library
cryptoapi.obj : error LNK2001: unresolved external symbol __imp__CertFreeCertificateContext@4
cryptoapi.obj : error LNK2001: unresolved external symbol __imp__CryptAcquireCertificatePrivateKey@24
cryptoapi.obj : error LNK2001: unresolved external symbol __imp__CertCloseStore@8
cryptoapi.obj : error LNK2001: unresolved external symbol __imp__CertOpenStore@20
cryptoapi.obj : error LNK2001: unresolved external symbol __imp__CertFindCertificateInStore@24
route.obj : error LNK2001: unresolved external symbol _GetIpForwardTable@12
route.obj : error LNK2001: unresolved external symbol _CreateIpForwardEntry@4
route.obj : error LNK2001: unresolved external symbol _DeleteIpForwardEntry@4
tun.obj : error LNK2001: unresolved external symbol _GetAdaptersInfo@8
tun.obj : error LNK2001: unresolved external symbol _IpReleaseAddress@4
tun.obj : error LNK2001: unresolved external symbol _GetInterfaceInfo@8
tun.obj : error LNK2001: unresolved external symbol _IpRenewAddress@4
tun.obj : error LNK2001: unresolved external symbol _AddIPAddress@20
tun.obj : error LNK2001: unresolved external symbol _FlushIpNetTable@4
tun.obj : error LNK2001: unresolved external symbol _DeleteIPAddress@4
tun.obj : error LNK2001: unresolved external symbol _GetAdapterIndex@8
Debug/openvpn.exe : fatal error LNK1120: 16 unresolved externals
Error executing link.exe.
openvpn.exe - 17 error(s), 1 warning(s)
首先解决crytoapi.obj?span lang="EN-US">lnk错误Q找?span lang="EN-US">crytoapi.c文g中的CertFreeCertificateContext 函数Q找到其声明:WinCrypt.h文gQ?span lang="EN-US">
#include <wincrypt.h> //需要装PLATFORM SDK
#pragma comment (lib, "crypt32.lib")
然后解决route.obj tun.obj的问题,也是通过route.c文g中的 GetIpForwardTable{其中一?span lang="EN-US">link错误的函敎ͼ扑ֈ其声明文?span lang="EN-US">:IPHlpApi.h
#include <iphlpapi.h>
#pragma comment (lib, "iphlpapi.lib")
最后再ơ编译,OKQ开始你?span lang="EN-US">openvpn代码调试吧!Q!
最q在VC 6.0上作業,有幾個地斚w遇到一個十分惱人的錯誤。就是出現下q的錯誤Q?span lang="EN-US"> Linking... nafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in LIBCMTD.lib(new.obj) nafxcwd.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCMTD.lib(dbgdel.obj) Debug/DCap.exe : fatal error LNK1169: one or more multiply defined symbols found
這樣的錯誤,明顯是兩個被link到的library都提供了同名的函式。但直接ignore?span lang="EN-US">LIBCMTD.lib當然是不行的Q因為它?span lang="EN-US">C?span lang="EN-US">library。之所以發生這個問,是因?span lang="EN-US">MFC?span lang="EN-US">library?span lang="EN-US">C?span lang="EN-US">library相衝H,必須a定它們被link的順序,也就是先nafxcwd.lib?span lang="EN-US">LIBCMTD.lib。但是這二者都?span lang="EN-US">default librariesQ所以要怎麼a定它們的順序呢?我找C個解法其實挺tricky的:先把它們分別都ignore掉,再額外將它們加入。也是說:?span lang="EN-US">Link頁籤上的Ignore Libraries輸入Q?span lang="EN-US">nafxcwd.lib libcmtd.libQ再到同一頁籤?span lang="EN-US">Object/library modules輸入Q?span lang="EN-US">nafxcwd.lib libcmtd.lib。這麼一來,加入它們的順序成了我們所弯a定的順序了?/span>
需要VC7或者以上,如下
VS.Net supports several macros that contain the name of the current function.
__FUNCDNAME__, __FUNCSIG__, __FUNCTION__
VC6 does not support them.
用VC7..........
1、将DLL目加入C工程中间Q?/p>
2、ALT+F7讄DLL属性,Link->Output file name里面的\径改Z工程目录Q?/p>
3、输出DLL的Debug版本C工程目录Q?/p>
4、设|断点在DLL源文件中QF5q行调试?/p>
Font: FixedsysQ?size:16
另外Qvc9 里面的Courier New字体也不错?br>
==============================================
备注Q?br>装VS2008Q不能有MMS Office 2007 Beta的东西,否则会在安装“Web创作lg?#8221;p|Q因为我遇到了这个问题?/p>
1)q行时库是 C run-time libraryQ是 C 而非 C++ 语言世界的概?取这个名字就是因Z?nbsp; C E序q行旉要这些库中的函数.
2)C 语言是所谓的“内?#8221;语言Q就其语a本n来说很小Q不多的关键字,E序程控制Q数据类型等Q;所以,C 语言内核开发出来之后,Dennis Ritchie ?nbsp; Brian Kernighan q C 本n重写?nbsp; 90% 以上?nbsp; UNIX pȝ函数Qƈ且把其中最常用的部分独立出来,形成头文件和对应?nbsp; LIBRARYQC run-time library 是q样形成的?nbsp;
3)随后Q随着 C 语言的流行,各个 C ~译器的生?个体/团体都遵循老的传统Q在不同q_上都有相对应?nbsp; Standard LibraryQ但大部分实现都是与各个q_有关的。由于各?nbsp; C ~译器对 C 的支持和理解有很多分歧和微妙的差别,所以就有了 ANSI CQANSI C Q主观意图上Q详l的规定?nbsp; C 语言各个要素的具体含义和~译器实现要求,引进了新的函数声明方式,同时订立?nbsp; Standard Library 的标准Ş式。所以Cq行时库q译器生商提供。至于由其他厂商/个h/团体提供的头文g和库函数Q应当称为第三方 C q行库(Third party C run-time librariesQ?nbsp;
4)C run-time library里面含有初始化代码,q有错误处理代码(例如divide by zero处理)。你写的E序可以没有math库,E序照样q行Q只是不能处理复杂的数学q算Q不q如果没有了C run-time库,main()׃会被调用Qexit()也不能被响应。因为C run-time library包含了CE序q行的最基本和最常用的函数?nbsp;
5)C C++ 世界里,有另外一个概?Standard C++ Library,它包括了上面所说的 C run-time library ?nbsp; STL。包?nbsp; C run-time library 的原因很明显QC++ ?nbsp; C 的超集,没有理由再重新来一?nbsp; C++ run-time library. VC针对C++ 加入的Standard C++ Library主要包括QLIBCP.LIB, LIBCPMT.LIB?nbsp; MSVCPRT.LIB
6)Windows环境下,VC提供?nbsp; C run-time library又分为动态运行时库和静态运行时库?nbsp;
动态运行时库主要是DLL库文件msvcrt.dll(or MSVCRTD.DLL for debug build),对应的Import library文g是MSVCRT.LIB(MSVCRTD.LIB for debug build)
静态运行时?release?对应的主要文件是Q?nbsp;
LIBC.LIB (Single thread static library, retail version)
LIBCMT.LIB (Multithread static library, retail version)
msvcrt.dll提供几千个C函数Q即使是像printfq么低的函数都在msvcrt.dll里。其实你的程序运行时Q很大一部分旉时在q些q行库里q行。在你的E序(release?被编译时QVC会根据你的编译选项(单线E、多U程或DLL)自动相应的q行时库文g(libc.lib,libcmt.lib或Import library msvcrt.lib)链接q来?
~译时到底哪个C run-time library联入你的E序取决于编译选项Q?nbsp;
/MD, /ML, /MT, /LD (Use Run-Time Library)
你可以VC中通过以下Ҏ讄选择哪个C run-time library联入你的E序Q?nbsp;
To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Code Generation in the Category box. See the Use Run-Time Library drop-down box.
从程序可UL性考虑,如果两函数都可完成一U功能,选运行时库函数好,因ؓ各个 C ~译器的生商对标准C Run-time library提供了统一的支?
大家都知道,从C/C++源程序到可执行文件要l历两个阶段:(1)~译器将源文件编译成汇编代码Q然后由汇编?assembler)译成机器指?再加上其它相关信?后输出到一个个目标文g(object file,VC的编译器~译出的目标文g默认的后~名是.obj)中;(2)链接?linker)一个个的目标文?或许q会有若q程序库)链接在一L成一个完整的可执行文件?
~译器编译源文g时会把源文g的全局W号(global symbol)分成?strong)和弱(weak)两类传给汇编器,而随后汇~器则将强弱信息~码q保存在目标文g的符可中。那么何谓强弱呢Q编译器认ؓ函数与初始化了的全局变量都是强符P而未初始化的全局变量则成了弱W号。比如有q么个源文g:
extern int errorno;
int buf[2] = {1,2};
int *p;
int main()
{
return 0;
}
其中main、buf是强W号Qp是弱W号Q而errorno则非强非弱,因ؓ它只是个外部变量的用声明?
有了强弱W号的概念,我们可以看看链接器是如何处理与选择被多ơ定义过的全局W号:
规则1: 不允许强W号被多ơ定?即不同的目标文g中不能有同名的强W号)Q?
规则2: 如果一个符号在某个目标文g中是强符P在其它文件中都是qP那么选择强符P
规则3: 如果一个符号在所有目标文件中都是qP那么选择其中L一个;
׃可知多个目标文g不能重复定义同名的函C初始化了的全局变量Q否则必然导致LNK2005和LNK1169两种链接错误。可是,有的时候我们ƈ没有在自qE序中发现这L重定义现象,却也遇到了此U链接错误,q又是何解?嗯,问题E微有点儿复杂,Ҏ慢慢道来?
众所周知QANSI C/C++ 定义了相当多的标准函敎ͼ而它们又分布在许多不同的目标文g中,如果直接以目标文件的形式提供l程序员使用的话Q就需要他们确切地知道哪个函数存在于哪个目标文件中Qƈ且在链接时显式地指定目标文g名才能成功地生成可执行文Ӟ昄q是一个巨大的负担。所以C语言提供了一U将多个目标文g打包成一个文件的机制Q这是静态程序库(static library)。开发者在链接时只需指定E序库的文g名,链接器就会自动到E序库中L那些应用E序实用到的目标模块,q把(且只?它们从库中拷贝出来参与构建可执行文g。几乎所有的C/C++开发系l都会把标准函数打包成标准库提供l开发者?有不q么做的吗?)?
E序库ؓ开发者带来了方便Q但同时也是某些混ؕ的根源。我们来看看链接器是如何解析(resolve)对程序库的引用的?br> 在符可?symbol resolution)阶段Q链接器按照所有目标文件和库文件出现在命o行中的顺序从左至右依ơ扫描它们,在此期间它要l护若干个集?(1)集合E是将被合q到一L成可执行文g的所有目标文仉合;(2)集合U是未解析W号(unresolved symbolsQ比如已l被引用但是q未被定义的W号)的集合;(3)集合D是所有之前已被加入到E的目标文件定义的W号集合。一开始,E、U、D都是I的?
(1): 对命令行中的每一个输入文件fQ链接器定它是目标文gq是库文Ӟ如果它是目标文gQ就把f加入到EQƈ把f中未解析的符号和已定义的W号分别加入到U、D集合中,然后处理下一个输入文件?
(2): 如果f是一个库文gQ链接器会尝试把U中的所有未解析W号与f中各目标模块定义的符可行匹配。如果某个目标模块m定义了一个U中的未解析符P那么把m加入到E中,q把m中未解析的符号和已定义的W号分别加入到U、D集合中。不断地对f中的所有目标模块重复这个过E直臛_达一个不动点(fixed point)Q此时U和D不再变化。而那些未加入到E中的f里的目标模块p单地丢弃Q链接器l箋处理下一输入文g?
(3): 如果处理q程中往D加入一个已存在的符P或者当扫描完所有输入文件时U非空Q链接器报错q停止动作。否则,它把E中的所有目标文件合q在一L成可执行文g?
VC带的~译器名字叫cl.exeQ它有这么几个与标准E序库有关的选项: /ML?MLd?MT?MTd?MD?MDd。这些选项告诉~译器应用程序想使用什么版本的C标准E序库?ML(~省选项)对应单线E静态版的标准程序库(libc.lib)Q?MT对应多线E静态版标准?libcmt.lib)Q此时编译器会自动定义_MT宏;/MD对应多线EDLL?导入库msvcrt.libQDLL是msvcrt.dll)Q编译器自动定义_MT和_DLL两个宏。后面加d的选项都会让编译器自动多定义一个_DEBUG宏,表示要用对应标准库的调试版Q因?MLd对应调试版单U程静态标准库(libcd.lib)Q?MTd对应调试版多U程静态标准库(libcmtd.lib)Q?MDd对应调试版多U程DLL标准?导入库msvcrtd.libQDLL是msvcrtd.dll)。虽然我们的在~译时明白无误地告诉了编译器应用E序希望使用什么版本的标准库,可是当编译器q完了活Q轮到链接器开工时它又如何得知一个个目标文g到底在思念谁?Z传递相思,我们的编译器干了点U密的勾当。在cl~译出的目标文g中会有一个专门的区域(兛_q个区域到底在文件中什么地方的朋友可以参考COFF和PE文g格式)存放一些指导链接器如何工作的信息,其中有一U就叫缺省库(default library)Q这些信息指定了一个或多个库文件名Q告诉链接器在扫描的时候也把它们加入到输入文g列表?当然序位于在命令行中被指定的输入文件之?。说到这里,我们先来做个实验。写个顶简单的E序Q然后保存ؓmain.c :
/* main.c */
int main() { return 0; }
用下面这个命令编译main.c(什么?你从不用命o行来~译E序Q这?.....) :
cl /c main.c
/c是告诉cl只编译源文gQ不用链接。因?ML是缺省选项Q所以上q命令也相当? cl /c /ML main.c 。如果没什么问题的?要出了问题才是活见鬼Q当焉非你的环境变量没有设|好Q这时你应该去VC的bin目录下找到vcvars32.bat文g然后q行它?Q当前目录下会出C个main.obj文gQ这是我们可爱的目标文件。随便用一个文本编辑器打开?是的Q文本编辑器Q大胆地d别害?Q搜?defaultlib"字符Ԍ通常你就会看到这L东西: "-defaultlib:LIBC -defaultlib:OLDNAMES"。啊哈,没错Q这?br>是保存在目标文g中的~省库信息。我们的目标文g昄指定了两个缺省库Q一个是单线E静态版标准库libc.lib(q与/ML选项相符)Q另外一个是oldnames.lib(它是Z兼容微Y以前的C/C++开发系l??
VC的链接器是link.exeQ因为main.obj保存了缺省库信息Q所以可以用
link main.obj libc.lib
或?
link main.obj
来生成可执行文gmain.exeQ这两个命o是等L。但是如果你?
link main.obj libcd.lib
的话Q链接器会给Z个警? "warning LNK4098: defaultlib "LIBC" conflicts with use of other libs; use /NODEFAULTLIB:library"Q因Z昑ּ指定的标准库版本与目标文件的~省g一致。通常来说Q应该保证链接器合ƈ的所有目标文件指定的~省标准库版本一_否则~译器一定会l出上面的警告,而LNK2005和LNK1169链接错误则有时会出现有时不会。那么这个有时到底是什么时候?呵呵Q别着急,下面的一切正是ؓ喜欢q根I底的你准备的?
Z个源文gQ就叫mylib.cQ内容如?
/* mylib.c */
Qi nclude
void foo()
{
printf("%s","I am from mylib!\n");
}
?
cl /c /MLd mylib.c
命o~译Q注?MLd选项是指定libcd.lib为默认标准库。lib.exe是VC自带的用于将目标文g打包成程序库的命令,所以我们可以用
lib /OUT:my.lib mylib.obj
mylib.obj打包成库Q输出的库文件名是my.lib。接下来把main.cҎ:
/* main.c */
void foo();
int main()
{
foo();
return 0;
}
?
cl /c main.c
~译Q然后用
link main.obj my.lib
q行链接。这个命令能够成功地生成main.exe而不会生LNK2005和LNK1169链接错误Q你仅仅是得C一条警告信?"warning LNK4098: defaultlib "LIBCD" conflicts with use of other libs; use /NODEFAULTLIB:library"。我们根据前文所q的扫描规则来分析一下链接器此时做了些啥?
一开始E、U、D都是I集Q链接器首先扫描到main.objQ把它加入E集合Q同时把未解析的foo加入UQ把main加入DQ而且因ؓmain.obj的默认标准库是libc.libQ所以它被加入到当前输入文g列表的末。接着扫描my.libQ因是个库,所以会拿当前U中的所有符?当然现在׃个foo)与my.lib中的所有目标模?当然也只有一个mylib.obj)依次匚wQ看是否有模块定义了U中的W号。结果mylib.obj实定义了fooQ于是它被加入到EQfoo从U转移到DQmylib.obj引用的printf加入到UQ同样地Qmylib.obj指定的默认标准库是libcd.libQ它也被加到当前输入文g列表的末?在libc.lib的后?。不断地在my.lib库的各模块上q行q代以匹配U中的W号Q直到U、D都不再变化。很明显Q现在就已经到达了这么一个不动点Q所以接着扫描下一个输入文Ӟ是libc.lib。链接器发现libc.lib里的printf.obj里定义有printfQ于是printf从UUdDQ而printf.obj被加入到EQ它定义的所有符号加入到DQ它里头的未解析W号加入到U。链接器q会把每个程序都要用到的一些初始化操作所在的目标模块(比如crt0.obj{?及它们所引用的模?比如malloc.obj、free.obj{?自动加入到E中,q更新U和D以反应这个变化。事实上Q标准库各目标模块里的未解析W号都可以在库内其它模块中找到定义,因此当链接器处理完libc.libӞU一定是I的。最后处理libcd.libQ因为此时U已经为空Q所以链接器会抛弃它里面的所有目标模块从而结束扫描,然后合ƈE中的目标模块q输出可执行文g?
上文描述了虽然各目标模块指定了不同版本的~省标准库但仍然链接成功的例子,接下来你目睹因U不严}而导致的悲惨p|?
修改mylib.c成这个样?
Qi nclude
void foo()
{
// just a test , don"t care memory leak
_malloc_dbg( 1, _NORMAL_BLOCK, __FILE__, __LINE__ );
}
其中_malloc_dbg不是ANSI C的标准库函数Q它是VC标准库提供的malloc的调试版Q与相关函数配套能帮助开发者抓各种内存错误。用它一定要定义_DEBUG宏,否则预处理器会把它自动{为malloc。l用
cl /c /MLd mylib.c
lib /OUT:my.lib mylib.obj
~译打包。当再次?
link main.obj my.lib
q行链接Ӟ我们看到了什么?天哪Q一堆的LNK2005加上个贵?fatal error"的LNK1169垫底Q当然还不了那个LNK4098。链接器是不是疯了?不,你冤枉可怜的链接器了Q我拍胸脯保证它可是一直在心责地照章办事?
一开始E、U、D为空Q链接器扫描main.objQ把它加入EQ把foo加入UQ把main加入DQ把libc.lib加入到当前输入文件列表的末尾。接着扫描my.libQfoo从U转移到DQ_malloc_dbg加入到UQlibcd.lib加到当前输入文g列表的尾部。然后扫描libc.libQ这时会发现libc.lib里Q何一个目标模块都没有定义_malloc_dbg(它只在调试版的标准库中存?Q所以不会有M一个模块因为_malloc_dbg而加入EQ但是每个程序都要用到的初始化模?如crt0.obj{?及它们所引用的模?比如malloc.obj、free.obj{?q是会自动加入到E中,同时U和D被更C反应q个变化。当链接器处理完libc.libӞU只剩_malloc_dbgq一个符受最后处理libcd.libQ发现dbgheap.obj定义了_malloc_dbgQ于是dbgheap.obj加入到EQ它里头的未解析W号加入UQ它定义的所有其它符号也加入DQ这时灾难便来了。之前malloc{符号已l在D?随着libc.lib里的malloc.obj加入E而加入的)Q而dbgheap.obj又定义了包括malloc在内的许多同名符Pq引发了重定义冲H,链接器只好中断工作ƈ报告错误?
现在我们该知道,链接器完全没有责任,责Q在我们自qw上。是我们_心地把~省标准库版本不一致的目标文g(main.obj)与程序库(my.lib)链接hQ导致了大灾难。解军_法很单,要么?MLd选项来重~译main.cQ要么用/ML选项重编译mylib.c?
在上qC子中Q我们拥有库my.lib的源代码(mylib.c)Q所以可以用不同的选项重新~译q些源代码ƈ再次打包。可如果使用的是W三方的库,它ƈ没有提供源代码,那么我们只有改变自q序的~译选项来适应q些库了。但是如何知道库中目标模块指定的默认库呢Q其实VC提供的一个小工具便可以完成Q务,q就是dumpbin.exe。运行下面这个命?
dumpbin /DIRECTIVES my.lib
然后在输ZN?Linker Directives"引导的信息,你一定会发现每一处这L信息都会包含若干个类?-defaultlib:XXXX"q样的字W串Q其中XXXX便代表目标模块指定的~省库名?
知道了第三方库指定的默认标准库,再用合适的选项~译我们的应用程序,可以避免LNK2005和LNK1169链接错误。喜ƢIDE的朋友,你一样可以到 "Project属? -> "C/C++" -> "代码生成(code generation)" -> "q行时库(run-time library)" 下讄应用E序的默认标准库版本Q这与命令行选项的效果是一L?
l极解决办法Q?/strong> ?Project/Setting/Link/General中的 Project Options: 加入 /FORCE:MULTIPLE卛_?
#pragma pack(push,1)
struct RateInfoOld
{
time_t ctm; // rate time
int open; // open price: 11987=119.87
short high,low,close; // high,low,close shift from open
double vol; // volume
};
#pragma pack(pop)
是的QDOS是不会说假话的,不像Windows一hL重要的东襉K藏v来不让你看到——如果你所在的不是根目录,你将会看到?”与?.”这两个目录——这是在资源理器中看不到的。从DOS时代走过的朋友们大抵都明白吧Q一个点代表的是当前目录Q两个点代表的是上一U目录。那么我在处理信息时Q就一定得把它们两个过滤出去,原因我在下面解释。do-whileD늚代码如下Q?br>do
{
if (wfd.cFileName[0] == '.')
continue; // qoq两个目?br> if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
TCHAR szFile[MAX_PATH];
if (IsRoot(lpszPath))
wsprintf(szFile, "%s%s", lpszPath, wfd.cFileName);
else
wsprintf(szFile, "%s\\%s", lpszPath, wfd.cFileName);
function(szFile); // 如果扑ֈ的是目录Q则q入此目录进行递归
}
else
{
// Ҏ件进行操?br> }
} while (FindNextFile(hFind, &wfd));
FindClose(hFind); // 关闭查找句柄
现在我来解释Z么要把那两个带点的目录过滤出厅R如你所见,如果扑ֈ的是目录Q那么进入此目录q行递归——那么若是当前目录呢Q答案很明显Q如果不对其q行qoQ那么程序将q入“当前目录”进行递归。是的,如是导致递归无休止地q行下去?br> 法p么多了,׃q是一个极其耗费pȝ资源的算法,因此你在E序中用到它的时候,最好将其放C个单独的U程中运行,否则会D你的E序在查找过E中没有M响应?br> 附:IsRoot函数源码
BOOL IsRoot(LPCTSTR lpszPath)
{
TCHAR szRoot[4];
wsprintf(szRoot, "%c:\\", lpszPath[0]);
return (lstrcmp(szRoot, lpszPath) == 0);
}
解决办法Q{到Stdafx.cppQClean, Ctrl + F7重新~译Stdafx.cpp, 然后F7~译工程卛_解决?/p>
U程本地存储 (TLS) 是一个方法,通过该方法,l定的多U程q程中的每个U程都可以分配存储线E特定数据的位置。通过 TLS APIQTlsAlloc、TlsGetValue、TlsSetValue、TlsFreeQ方式支持动态绑定(q行Ӟ的线E特定数据。除了现有的 API 实现QWin32 ?Visual C++ ~译器现在还支持静态绑定(加蝲旉Q基于线E的数据?
通过 Win32 API 层和~译器实现“线E本地存储”。有兌l信息,请参?Win32 API 文档中的 TlsAlloc、TlsGetValue、TlsSetValue ?TlsFree?
Visual C++ ~译器包括ɾU程本地存储操作更加自动化的关键字,而不是通过 API 层。将在下一节(TLS 的编译器实现Q描q此语法?
Z支持 TLSQ已新属?thread dC C ?C++ 语言Qƈ?Visual C++ ~译器支持。此属性是一个扩展存储类修饰W,如上一节中所q。?__declspec 关键字声?thread 变量。例如,以下代码声明了一个整数线E局部变量,q用一个值对其进行初始化Q?pre>__declspec( thread ) int tls_i = 1;
TLS 的规则和限制
声明静态绑定线E的本地对象和变量时必须遵守下列原则Q?
#define Thread __declspec( thread ) Thread void func(); // This will generate an error.
#define Thread __declspec( thread ) void func1() { Thread int tls_i; // This will generate an error. } int func2( Thread int tls_i ) // This will generate an error. { return tls_i; }
#define Thread __declspec( thread ) extern int tls_i; // This will generate an error, since the int Thread tls_i; // declaration and definition differ.
char __declspec( thread ) *ch; // Error
#define Thread __declspec( thread ) class Thread C // Error: classes cannot be declared Thread. { // Code }; C CObject;
因ؓ允许使用 thread 属性的 C++ 对象的声明,因此下面两个CZ在语义上是等效的Q?
#define Thread __declspec( thread ) Thread class B { // Code } BObject; // OK--BObject is declared thread local. class B { // Code }; Thread B BObject; // OK--BObject is declared thread local.
#define Thread __declspec( thread ) Thread int tls_i; int *p = &tls_i; //This will generate an error in C.
但是Q此限制不适用?C++。因?C++ 允许动态初始化所有对象,因此可以用用线E本地变量地址的表辑ּ初始化对象。实现此操作的方式与实现U程本地对象l构的方式相同。例如,以上昄的代码在作ؓ C++ 源文件编译时不会生成错误。请注意Q只有在其中获取地址的线E仍然存在的情况下,U程本地变量的地址才有效?
#define Thread __declspec( thread ) Thread int tls_i = tls_i; // Error in C and C++ int j = j; // OK in C++, error in C Thread int tls_i = sizeof( tls_i ) // Legal in C and C++
h意:包含正在初始化的对象?sizeof
表达式不建立对自w的引用且在 C ?C++ 中都是合法的?
C++ 不允许此cdU程数据的动态初始化Q因为将来可能要对线E本地存储功能进行增强?
Home | Overview | How Do I | Compiler Options
This option writes preprocessor output to a file with the same base name as the source file, but with the .I extension. It adds #line directives to the output file at the beginning and end of each included file and around lines removed by preprocessor directives that specify conditional compilation. The preprocessed listing file is identical to the original source file, except that all preprocessor directives are carried out, and macro expansions are performed.
This option suppresses compilation; CL does not produce an .OBJ file, even if the /Fo option is specified. The /P option also suppresses production of the alternate output files created by the /FA, /Fa, or /Fm option.
The /P option is similar to the /E and /EP options. Using /EP with /P suppresses placement of #line directives in the output file.
The following table summarizes the actions of the /E, /EP, and /P options.
Option | Preprocessor output includes #line directives? | Output sent to |
/E | Yes | stdout |
/P | Yes | .i file |
/EP | No | stdout |
/E /EP | No | stdout |
/P /EP | No | .i file |
1、一般用/P /EP,q样没?line了,生成的是.i文g
2、利用这个,可以看有很多复杂宏,预编译之后的源代码,比如stlQ?boost{,#include的代码和相关代码Q都会是被剥d的,出现在同一个文仉Q这个对于阅M码比较有用?/font>