当前位置:编程学习 > C/C++ >>

学习windows编程(4)--从libc.lib开始

乱想乱写飞舞之空间
从零开始,学习windows编程(4)--从libc.lib开始
从上一篇文章中,大家已经了解到有C运行时库这个概念,这个不算是新东西,但是一般都隐藏在幕后,C/C++语言教学的时候不讲,windows/linux编程的时候似乎也不会专门讲到。不过它一般是我们C/C++编程中默认会使用的一个重要部分。回想想,我们随手打出的strcpy, memset, memcpy等等,不就是C运行时库所提供出来的东西吗?

既然这样,就要好好研究一下这个东西了。

前面已经说过,针对单线程/多线程,静态/动态链接,是否是debug版本,VC6的C运行时库提供了6个版本。具体可以看下面的截图。

 image

而其中每一个选择对应的LIB文件,在上一篇中已经有一个列表介绍了,这里就不重复写了。这里也不全部一下子将所有的都研究一下,还是按照由浅入深的原则,从最简单的部分开始,当然,也会在牵涉到其他部分的时候,进行一定的说明。

最简单的当然是Single-Threaded,同时也是static link的了。其对应的文件为LIBC.LIB。对应CL的编译选项为/ML。

既然要研究这个LIB文件,那当然是有源码最好了,jjhou不是说过,“源码面前,了无秘密”吗。那我们在哪里找到有源码呢?

只要你安装了VC6,它就带有CRT的源码,具体目录和你安装VC6的目录有关,在我电脑上的路径为“d:Program FilesMicrosoft Visual StudioVC98CRTSRC”,你进去之后会发现,里面有不少熟悉的名字,如“MATH.H”、“STDIO.H”、“STDLIB.H”、“STRING.H”等,由于C运行时库被C++运行时库包含,所以这里面还有C++标准库的代码,所以还能看到“IOSTREAM”、“CSTDIO”、“algorithm”等C++的std头文件。

这里就出现了一个问题,这里的文件有成百上千个,我们一个个全部看是不可能的,那如何找出关键的部分来呢?

如果还对上一篇的分析有印象,并且带有问题的同学,应该很容易联想到,我们在link不带有defaultlibs信息的hello.obj文件时,出现了两个LINK2001错误,分别是找不到_printf和_mainCRTStartup这两个symbol文件。

编译器CL在编译C程序的时候,内部将需要编译的函数前面加上下划线(_)用来标识,_printf具体指的就是printf函数,_mainCRTStartup则是mainCRTStartup,是在哪里使用的呢?

我们已经知道,printf函数和mainCRTStartup函数的实现都是在LIBC.LIB中,printf,是我们main函数中用来打印信息的,而mainCRTStartup,则是hello.exe的入口(entry point)。

入口

学过C语言的人都知道,有一个main函数,是一个程序的入口。不管怎样,main函数是特殊的。在TCPL (“The C programming Language” by K&R) 的1.1章节,介绍Hello World的时候说的一段话:

Now, for some explanations about the program itself. A C program, whatever its size, consists of functions and variables. A function contains statements that specify the computing operations to be done, and variables store values used during the computation. C functions are like the subroutines and functions in Fortran or the procedures and functions of Pascal. Our example is a function named main. Normally you are at liberty to give functions whatever names you like, but “main” is special - your program begins executing at the beginning of main. This means that every program must have a main somewhere.

因为这一段话,因为这本书的经典,很多人包括我思路都很难转变。一直都认为main就是C程序的入口函数。不过,真的是这样吗?

使用汇编的童鞋都知道,汇编的入口函数只是一个符号,是可以随意定义的,之后就从入口开始,PC一条条的开始执行汇编代码。对于C程序来说,main也是一个符号而已,不过这个符号与汇编的_start有些区别,_start可以用其他符号直接代替,而在windows系统下,VC开发的环境中,我们的hello.exe的main函数之前还有一个mainCRTStartup(呼,好多限制条件,好绕口……)。

crt0.c

为什么需要mainCRTStartup呢,我们还是要看一下源码实现。先搜索到mainCRTStartup所在的文件,为crt0.c,其全部代码如下:

show sourceview sourceprint?001 /*** 

002 *crt0.c - C runtime initialization routine 

003 * 

004 *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved. 

005 * 

006 *Purpose: 

007 *       This the actual startup routine for apps.  It calls the users main 

008 *       routine [w]main() or [w]WinMain after performing C Run-Time Library 

009 *       initialization. 

010 * 

011 *       (With ifdefs, this source file also provides the source code for 

012 *       wcrt0.c, the startup routine for console apps with wide characters, 

013 *       wincrt0.c, the startup routine for Windows apps, and wwincrt0.c, 

014 *       the startup routine for Windows apps with wide characters.) 

015 * 

016 *******************************************************************************/

017   

018 #ifdef _WIN32 

019   

020 #ifndef CRTDLL 

021   

022 #include <cruntime.h> 

023 #include <dos.h> 

024 #include <internal.h> 

025 #include <stdlib.h> 

026 #include <string.h> 

027 #include <rterr.h> 

028 #include <windows.h> 

029 #include <awint.h> 

030 #include <tchar.h> 

031 #include <dbgint.h> 

032   

033 /* 

034  * wWinMain is not yet defined in winbase.h. When it is, this should be 

035  * removed. 

036  */

037   

038 int

039 WINAPI 

040 wWinMain( 

041     HINSTANCE hInstance, 

042     HINSTANCE hPrevInstance, 

043     LPWSTR lpCmdLine, 

044     int nShowCmd 

045     ); 

046   

047 #ifdef WPRFLAG 

048 _TUCHAR * __cdecl _wwincmdln(void); 

049 #else  /* WPRFLAG */ 

050 _TUCHAR * __cdecl _wincmdln(void); 

051 #endif  /* WPRFLAG */ 

052   

053 /* 

054  * command line, environment, and a few other globals 

055  */

056   

057 #ifdef WPRFLAG 

058 wchar_t *_wcmdln;           /* points to wide command line */

059 #else  /* WPRFLAG */ 

060 char *_acmdln;              /* points to command line */

061 #endif  /* WPRFLAG */ 

062   

063 char *_aenvptr = NULL;      /* points to environment block */

064 wchar_t *_wenvptr = NULL;   /* points to wide environment block */

065   

066   

067 void (__cdecl * _aexit_rtn)(int) = _exit;   /* RT message return procedure */

068   

069 static void __cdecl fast_error_exit(int);   /* Error exit via ExitProcess */

070   

071 /* 

072  * _error_mode and _apptype, together, determine how error messages are 

073  * written out. 

074  */

075 int __error_mode = _OUT_TO_DEFAULT; 

076 #ifdef _WINMAIN_ 

077 int __app_type = _GUI_APP;&n

补充:软件开发 , C语言 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,