您的位置:首页 > 其它

VC中编译、运行程序的小知识点

2011-10-11 11:32 471 查看
http://topic.csdn.net/t/20050428/22/3974737.html

 1、Run-Time
  Library 

Run-Time   Library是编译器提供的标准库,提供一些基本的库函数和系统调用。 

我们一般使用的Run-Time   Library是C   Run-Time   Libraries。当然也有Standard   C++   libraries。   

C   Run-Time   Libraries实现ANSI   C的标准库。VC安装目录的CRT目录有C   Run-Time库的大部分源代码。   

C   Run-Time   Libraries有静态库版本,也有动态链接库版本;有单线程版本,也有多线程版本;还有调试和非调试版本。 

可以在 "project "- "settings "- "C/C++ "- "Code   Generation "中选择Run-Time   Library的版本。 

动态链接库版本: 

/MD   Multithreaded   DLL   使用导入库MSVCRT.LIB 

/MDd   Debug   Multithreaded   DLL   使用导入库MSVCRTD.LIB 

静态库版本: 

/ML   Single-Threaded   使用静态库LIBC.LIB   

/MLd   Debug   Single-Threaded   使用静态库LIBCD.LIB 

/MT   Multithreaded   使用静态库LIBCMT.LIB 

/MTd   Debug   Multithreaded   使用静态库LIBCMTD.LIB 

C   Run-Time   Library的标准io部分与操作系统的关系很密切,在Windows上,CRT的io部分代码只是一个包装,底层要用到操作系统内核kernel32.dll中的函数,在编译时使用导入库kernel32.lib。这也就是为什么在嵌入式环境中,我们一般不能直接使用C标准库。 

在Linux环境当然也有C标准库,例如: 

ld   -o   output   /lib/crt0.o   hello.o   -lc 

参数 "-lc "就是在引用C标准库libc.a。猜一猜 "-lm "引用哪个库文件? 

2、常见的编译参数 

VC建立项目时总会定义 "Win32 "。控制台程序会定义 "_CONSOLE ",否则会定义 "_WINDOWS "。Debug版定义 "_DEBUG ",Release版定义 "NDEBUG " 

与MFC   DLL有关的编译常数包括: 

_WINDLL   表示要做一个用到MFC的DLL 

_USRDLL   表示做一个用户DLL(相对MFC扩展DLL而言)   

_AFXDLL   表示使用MFC动态链接库 

_AFXEXT   表示要做一个MFC扩展DLL 

所以: 

Regular,   statically   linked   to   MFC   _WINDLL,_USRDLL   

Regular,   using   the   shared   MFC   DLL   _WINDLL,_USRDLL,_AFXDLL 

Extension   DLL   _WINDLL,_AFXDLL,_AFXEXT 

CL.EXE编译所有源文件,LINK.EXE链接EXE和DLL,LIB.EXE产生静态库。 

3、subsystem和可执行文件的启动 

LINK的时候需要指定/subsystem,这个链接选项告诉Windows如何运行可执行文件。 

控制台程序是/subsystem: "console " 

其它程序一般都是/subsystem: "windows   " 

将   subsystem   选成 "console "后,Windows在进入可执行文件的代码前(如mainCRTStartup),就会产生一个控制台窗口。 

如果选择 "windows ",操作系统就不产生console窗口,该类型应用程序的窗口由用户自己创建。 

可执行文件都有一个Entry   Point,LINK时可以用/entry指定。缺省情况下,如果subsystem是“console”,Entry   Point是   mainCRTStartup(ANSI)或wmainCRTStartuup(UNICODE),即: 

/subsystem: "console "   /entry: "mainCRTStartup "   (ANSI) 

/subsystem: "console "   /entry: "wmainCRTStartuup "   (UNICODE) 

mainCRTStartup   或   wmainCRTStartuup   会调用main或wmain。 

值得一提的是,在进入应用程序的Entry   Point前,Windows的装载器已经做过C变量的初始化,有初值的全局变量拥有了它们的初值,没有初值的变量被设为0。 

如果subsystem是“windows”,Entry   Point是WinMain(ANSI)或wWinMain(UINCODE),即: 

/subsystem: "windows "   /entry: "WinMainCRTStartup "   (ANSI) 

/sbusystem: "windows "   /entry: "wWinMainCRTStartup "   (UINCODE) 

WinMainCRTStartup   或   wWinMainCRTStartup   会调用   WinMain   或   wWinMain。 

如果使用MFC框架,WinMain也会被埋藏在MFC库中(APPMODUL.CPP): 

extern   "C "   int   WINAPI 

_tWinMain(HINSTANCE   hInstance,   HINSTANCE   hPrevInstance, 

LPTSTR   lpCmdLine,   int   nCmdShow) 



//   call   shared/exported   WinMain 

return   AfxWinMain(hInstance,   hPrevInstance,   lpCmdLine,   nCmdShow); 



"_t "是一个宏,对于ANSI版本, "_tWinMain "就是 "WinMain ";对于UINCODE版本, "_tWinMain "就是 "wWinMain "。 

全局C++对象的构造函数是在什么地方调用的?答案是在进入应用程序的Entry   Point后,在调用main函数前的初始化操作中。所以MFC的theApp的构造函数是在_tWinMain之前调用的。 

4、不显示Console窗口的Console程序 

在默认情况下/subsystem   和/entry开关是匹配的,也就是: 

"console "对应 "mainCRTStartup "或者 "wmainCRTStartup " 

"windows "对应 "WinMain "或者 "wWinMain " 

我们可以通过手动修改的方法使他们不匹配。例如: 

#include   "windows.h " 

#pragma   comment(   linker,   "/subsystem:\ "windows\ "   /entry:\ "mainCRTStartup\ " "   )   //   设置入口地址   

void   main(void) 



MessageBox(NULL,   "hello ",   "Notice ",   MB_OK); 



这个Console程序就不会显示Console窗口。如果选/MLd的话,这个程序只需要链接LIBCD.LIB   user32.lib   kernel32.lib。 

5、VC中缺省库冲突的解决 

VC的编译器在编译程序时有两个习惯: 

a、在从头开始编译时,将源文件名按字母排序后,依次处理; 

b、一边编译一边决定需要哪些缺省库。   

它的这些习惯有时会造成奇怪的编译错误,例如项目中有两个文件: 

charutil.c 

gbnni.cpp 

其中gbnni.cpp用到了MFC库。 

它老兄当然是先处理charutil.c,然后觉得需要link一个C   Runtime库,根据项目设置选择了LIBCMTD.lib。 

然后又处理gbnni.cpp,因为要用MFC,又决定要link   nafxcwd.lib。 

最后link的时候,就会出现以下冲突: 

nafxcwd.lib(afxmem.obj)   :   error   LNK2005:   "void   __cdecl   operator   delete(void   *) "   (??3@YAXPAX@Z)   already   defined   in   LIBCMTD.lib(dbgdel.obj) 

其实,如果先link了nafxcwd.lib,就没有必要再link   LIBCMTD.lib,也就不会产生冲突。 

解决这类问题有两个办法。 

a、让项目的第一个文件包含MFC的头文件,这样编译器就不会想到找C   Runtime库。这样就要把c文件改成cpp了。 

b、将需要link   C   Runtime库的文件的名字改大一些,让它排在后面。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息