vc6.0编译c程序:VC中编译、运行程序的知识点



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"-"tings"-"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上CRTio部分代码只是个包装底层要用到操作系统内核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 表示要做个用到MFCDLL
_USRDLL 表示做个用户DLL(相对MFC扩展DLL而言)
_AFXDLL 表示使用MFC动态链接库
_AFXEXT 表示要做个MFC扩展DLL
所以:
Regular, ally linked to MFC _WINDLL,_USRDLL
Regular, using the shared MFC DLL _WINDLL,_USRDLL,_AFXDLL
Extension DLL _WINDLL,_AFXDLL,_AFXEXT

CL.EXE编译所有源文件LINK.EXE链接EXE和DLLLIB.EXE产生静态库

3、subsystem和可执行文件启动
LINK时候需要指定/subsystem这个链接选项告诉Windows如何运行可执行文件
控制台是/subsystem:"console"
其它般都是/subsystem:"windows "

将 subsystem 选成"console"后Windows在进入可执行文件代码前(如CRTStartup)就会产生个控制台窗口
如果选择"windows"操作系统就不产生console窗口,该类型应用窗口由用户自己创建

可执行文件都有个Entry PoLINK时可以用/entry指定缺省情况下如果subsystem是“console”Entry PoCRTStartup(ANSI)或wCRTStartuup(UNICODE)即:
/subsystem:"console" /entry:"CRTStartup" (ANSI)
/subsystem:"console" /entry:"wCRTStartuup" (UNICODE)
CRTStartup 或 wCRTStartuup 会或w
值得在进入应用Entry PoWindows装载器已经做过C变量有初值全局变量拥有了它们初值没有初值变量被设为0

如果subsystem是“windows”Entry Po是WinMain(ANSI)或wWinMain(UINCODE)即:
/subsystem:"windows" /entry:"WinMainCRTStartup" (ANSI)
/sbusystem:"windows" /entry:"wWinMainCRTStartup" (UINCODE)
WinMainCRTStartup 或 wWinMainCRTStartup 会 WinMain 或 wWinMain

这些入口点在CRT目录都可以看到源代码例如(为了简洁我删除了原代码些条件编译):

void CRTStartup(void)
{
ret;

/* Get the full Win32 version */
_osver = GetVersion;
_winminor = (_osver >> 8) & 0x00FF ;
_winmajor = _osver & 0x00FF ;
_winver = (_winmajor << 8) + _winminor;
_osver = (_osver >> 16) & 0x00FFFF ;

#def _MT
( !_heap_init(1) ) /* initialize heap */
# /* _MT */
( !_heap_init(0) ) /* initialize heap */
#end /* _MT */
fast_error_exit(_RT_HEAPINIT); /* write message and die */

#def _MT
( !_mtinit ) /* initialize multi-thread */
fast_error_exit(_RT_THREAD); /* write message and die */
#end /* _MT */

__try {
_ioinit; /* initialize lowio */
_acmdln = (char *)GetCommandLineA; /* get cmd line info */
_aenvptr = (char *)__crtGetEnvironmentStringsA; /* get environ info */
_argv;
_envp;
__initenv = _environ;
ret = (__argc, __argv, _environ);
exit(ret);
}
__except ( _XcptFilter(GetExceptionCode, GetExceptionInformation) )
{
_exit( GetExceptionCode ); /* Should never reach here */
} /* end of try - except */
} 如果使用MFC框架WinMain也会被埋藏在MFC库中(APPMODUL.CPP):
extern "C" WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, nCmdShow)
{
// call shared/exported WinMain
AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
对于ANSI版本"_tWinMain"就是"WinMain";对于UINCODE版本"_tWinMain"就是"wWinMain"可参见afx.h:



#def _UNICODE
# _t w
# _tWinMain wWinMain
#
# _t
# _tWinMain WinMain
#end

全局C对象构造是在什么地方?答案是在进入应用Entry Po化操作中所以MFCtheApp构造是在_tWinMain的前

4、不显示Console窗口Console
在默认情况下/subsystem 和/entry开关是匹配,也就是:
"console"对应"CRTStartup"或者"wCRTStartup"
"windows"对应"WinMain"或者"wWinMain"
我们可以通过手动修改思路方法使他们不匹配例如:

# "windows.h"
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"CRTStartup\"" ) // 设置入口地址
void (void)
{
MessageBox(NULL, "hello", "Notice", MB_OK);
}

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

其实如果不想看到Console窗口还有个更直接思路方法:那就是直接在EXE文件中将PE文件头Subsystem从3改成2在EXE文件中PE文件头偏移地址是0x3cSubsystem是个WORD它在PE文件头中偏移是0x5c

5、MFC库文件
MFC库可以静态链接也可以动态链接静态库和动态库又有Debug和ReleaseANSI和Unicode版本的分

静态MFC库主要有:
ANSI Debug NAFXCWD.LIB
ANSI Release NAFXCW.LIB
Unicode Debug UAFXCWD.LIB
Unicode Release UAFXCW.LIB

动态链接库主要有;
ANSI Debug MFCxxD.LIB (coreMFCxxD.DLL),
MFCOxxD.LIB (OLEMFCOxxD.DLL),
MFCDxxD.LIB (databaseMFCDxxD.DLL),
MFCNxxD.LIB (networkMFCNxxD.DLL),
MFCSxxD.LIB ()

ANSI Release MFCxx.LIB (combinedMFCxx.DLL)
MFCSxx.LIB ()

Unicode Debug MFCxxUD.LIB (coreMFCxxUD.DLL),
MFCOxxUD.LIB (OLEMFCOxxUD.DLL),
MFCDxxUD.LIB (databaseMFCDxxUD.DLL),
MFCNxxUD.LIB (networkMFCNxxUD.DLL),
MFCSxxUD.LIB ()

Unicode Release MFCxxU.DLL (combinedMFCxxU.DLL),
MFCSxxU.LIB ()

上面LIB文件除了MFCSxx(D、U、UD).LIB以外都是导入库
MFC动态链接库版本也需要静态链接些文件这些文件就放在MFCSxx(D、U、UD).LIB中例如包含_tWinMainappmodul.cpp

6、结束语
研究这些问题动机是想弄清楚我们是如何装载、运行但是由于Windows不是开源平台我也只能研究到PE文件(Windows上可执行文件格式)entry po、subsystem都是PE文件头部分

Windows在进入PE文件entry po的前做了些什么就看不到了只能大概推测:应该是创建个进程装载PE文件和所有需要DLL化C变量然后从某个起点开始运行区别subsystem应该有区别起点这个起点时应该传入PE文件entry po地址
Tags:  vc如何编译c程序 vc编译程序 vc编译c程序 vc6.0编译c程序

延伸阅读

最新评论

发表评论