程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 學習windows編程(4)--從libc.lib開始

學習windows編程(4)--從libc.lib開始

編輯:關於C語言

亂想亂寫飛舞之空間
從零開始,學習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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved