導航:首頁 > 源碼編譯 > 微軟c類庫的源碼

微軟c類庫的源碼

發布時間:2023-01-07 18:31:04

A. 怎麼查看微軟C#類庫的源碼

微軟c#類庫源碼你可以在微軟網站上直接查看
https://referencesource.microsoft.com/
當然上面也可以download到本地查看

B. 如何查看C語言,內庫的源代碼

1、首先標准只是規定了這些函數的介面和具體的運行效率的要求,這些函數具體是怎麼寫得要看各個編譯器的實現和平台。
2、例如使用的編譯器是visual studio,微軟提供了一部分C運行時(CRT)的源碼,裡面會有memcpy,strcpy之類的函數的實現,在visual studio 2005下的路徑是C:\Program Files\Microsoft Visual Studio 8\VC\crt\src。

C. 用什麼軟體來查看一個用Microsoft Visual C++ 6.0 編寫的程序的源代碼

標 題: MFC逆向初級研究(1)
作 者: 北斗之搖光
時 間: 2007-03-15 17:14
鏈 接: http://bbs.pediy.com/showthread.php?t=41087
詳細信息:

【文章標題】: MFC逆向初級研究(1)
【文章作者】: 北斗之搖光
【作者郵箱】: [email protected]
【下載地址】: 自己搜索下載
【作者聲明】: 只是感興趣,沒有其他目的。失誤之處敬請諸位大俠賜教!
--------------------------------------------------------------------------------
【詳細過程】
引言
本文主要針對微軟的VC++6.0中使用MFC產生的EXE文件的逆向研究,我曾經使用微軟的Visual Studio 2005編譯了一
個EXE文件,通過IDA反匯編以後發現該文件與VC++6.0產生的文件還是有所區別,因此特別在此聲明一下。文中主要使用了I
DA pro 5.0和在看雪(www.pediy.com)下載的OllyICE作為工具對目標文件進行反匯編。在此也感謝看雪論壇的各位的無私奉
獻,在研究過程的中的困難多通過各位的帖子得到了幫助。
逆向的關鍵
我認為逆向的關鍵主要是要弄明白目標文件的演算法和實現過程,在Window操作系統下,軟體的實現過程就體現在其
對Window消息的處理,而軟體的演算法則包含在處理的具體過程中。對於通過SDK編寫的"傳統"的Windows應用程序基本都具備
幾個共同的特徵:WinMain函數、WinProc函數、窗口注冊、消息循環。對於這類目標文件的分析主要集中的WinProc的分析上
,WinProc的函數地址獲得一般是通過窗口注冊函數中的參數獲得。(由於我對於這類文件沒有具體逆向過,所以只是大概的
說說,有不對的地方請各位不要客氣,盡管拍磚)
而使用MFC(Microsoft Function Class)顧名思義,該類庫主要封裝了大部分的Windows API函數所以在代碼中看
不到原本的SDK編程中的消息循環、窗口過程函數等等東西,所有這些封裝在相應的mfcxx.dll中,讓程序員能夠專著與處理
過程與演算法。這種做法於逆向而言有好處也有壞處:
壞處就是加大了對於MFC產生的EXE文件的逆向難度,讓許多的和我一樣的菜鳥迷失在匯編代碼中找不找北了,基本主要就靠
猜測實現過程中用到了那些函數,然後對文件導入表的函數下斷點來尋找我們所需要的處理過程;
好處就是這樣的做法使得EXE文件中主要都是目標程序的Window消息處理流程以及演算法,而且dll中的大部分函數的功能都能
在MSDN中查到。如果能夠通過對目標文件的分析得到這個Window消息處理流程和演算法架構,基本上我們就可以重寫整個軟體;
要做到上面的目標,首先我們要對MFC有所了解,推薦沒有基礎的兄弟們讀讀候俊傑的《深入淺出MFC》。該書在逆向過
程中完全可以作為一本參考書,讓你能通過源代碼了解實現過程,網上有很多該書的電子版下載。
一個逆向MFC產生的EXE文件的例子
下面我們就通過一個具體的例子來學習一下如何從目標文件中挖到我們需要的東西。首先我們來產生一個需要的EXE文件。
在此我假定各位對MFC有過一定的使用經驗,畢竟逆向分析才是本文的重點。
1.產生例子所需要的目標文件:
我們通過VC++6.0的向導來產生一個名為ReverseMFC的工程,這個工程的設置情況如下:
Application type of fff:
Dialog-Based Application targeting:
Win32
Classes to be created:
Application: CFffApp in ReverseMFC.h and ReverseMFC.cpp
Dialog: CFffDlg in ReverseMFCDlg.h and ReverseMFCDlg.cpp
Features:
+ Uses shared DLL implementation (MFC42.DLL)
+ Localizable text in:
中文[中國]
直接編譯以後就能夠運行,為了確定我們是否正確的分析的整個目標文件,在該對話框中加入一個我們自定義的按鈕如
下,對於該按鈕的處理函數如下設定為:
AfxMessageBox("I find it!",MB_OK);編譯後就得到了我們需要的目標文件。
現在我們得到了所需要的目標文件,在IDA中載入該文件。在此我們最好是產生Release版本的EXE文件,畢竟所有的發
布軟體都是Release版本的。
2.具體分析
在IDA中按Ctrl+S找到.rdata段,該段主要存儲了目標文件的類運行時創建信息、MessageMap信息、MessageEntry信息、
虛函數表、RTTI數據(如果編譯選項中選擇了支持RTTI的話)。
在到達.rdata段後我們可以看到這樣的代碼,對數據進行格式轉換後可以得到如下圖所示的數據。
.rdata:004021C0 ; 屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯?
.rdata:004021C0
.rdata:004021C0 ; Segment type: Pure data
.rdata:004021C0 ; Segment permissions: Read
.rdata:004021C0 _rdata segment para public 'DATA' use32
.rdata:004021C0 assume cs:_rdata
.rdata:004021C0 ;org 4021C0h
.rdata:004021C0 off_4021C0 dd offset sub_401000 ; DATA XREF: sub_401010o
.rdata:004021C4 dd offset dword_4021C8
.rdata:004021C8 dword_4021C8 dd 111h ; DATA XREF: .rdata:004021C4o
.rdata:004021CC dd 0
.rdata:004021D0 dd 0E146h
.rdata:004021D4 dd 0E146h
.rdata:004021D8 dd 0Ch
.rdata:004021DC dd offset CWinApp::OnHelp(void)
.rdata:004021E0 dd 0
.rdata:004021E4 dd 0
.rdata:004021E8 dd 0
.rdata:004021EC dd 0
.rdata:004021F0 dd 0
.rdata:004021F4 dd 0
.rdata:004021F8 off_4021F8 dd offset CWinApp::GetRuntimeClass(void)
.rdata:004021F8 ; DATA XREF: unknown_libname_1-56o
.rdata:004021FC dd offset sub_401040
.rdata:00402200 dd offset nullsub_2
.rdata:00402204 dd offset nullsub_3
.rdata:00402208 dd offset nullsub_2
.rdata:0040220C dd offset CCmdTarget::OnCmdMsg(uint,int,void *,AFX_CMDHANDLERINFO *)
其中的off_4021C0就是一個MessageMap數據;dword_4021C8就是MessageMap所指的MessageEntry數據;off_4021F8就是一個
類的虛函數表的開始位置。那麼具體這些數據時那個類的相關數據呢?如此判斷的依據是什麼?
首先我們知道MessageEntry是的數據結構定義如下,而且以6個0表示整個數組的結束。
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // windows message
UINT nCode; // control code or WM_NOTIFY code
UINT nID; // control ID (or 0 for windows messages)
UINT nLastID; // used for entries specifying a range of control id's
UINT nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
因此我們有理由假設"dword_4021C8就是MessageMap所指的MessageEntry數據"。
而MessageMap數據結構定義如下:
struct AFX_MSGMAP
{
#ifdef _AFXDLL
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
#else
const AFX_MSGMAP* pBaseMap;
#endif
const AFX_MSGMAP_ENTRY* lpEntries;
};
off_4021C0的兩個數據中第二個數據恰恰就是我們前面假設為MessageEntry的指針,跟入其第一個數據,我們看到如下的代
碼:
.text:00401000 ; *************** S U B R O U T I N E ***************************************
.text:00401000
.text:00401000
.text:00401000 sub_401000 proc near ; DATA XREF: .rdata:off_4021C0o
.text:00401000 mov eax, ds:AFX_MSGMAP const CWinApp::messageMap
.text:00401005 retn
.text:00401005
.text:00401005 sub_401000 endp
恰恰是一個返回基類的MessageMap的函數。因此我們也同樣有理由假設"off_4021C0就是一個MessageMap數據"。
對於虛函數表的假設是如何被證明呢?首先我們要知道關於虛函數表的一點知識:虛函數表由虛函數的地址組成,表中函數
地址的順序和它們第一次出現的順序(即在類定義的順序)一致。若有重載的函數,則替換掉基類函數的地址。通過這個我
們可以知道MFC中虛函數表中的函數順序必然是先按照CObject->CCmdtarget->。。。。這個類繼承順序中的虛函數順序來處
理虛函數表中的函數順序的。只要證明這個我們"假設的虛函數"中的函數順序與上面提到的知識相符合則有理由說明我們的
假設成立。
首先來看CObject中虛函數的順序,在查看CObject的聲明文件後得到了這個類的虛函數順序:
virtual CRuntimeClass* GetRuntimeClass() const;
virtual ~CObject(); // virtual destructors are necessary
virtual void Serialize(CArchive& ar);
#if defined(_DEBUG) || defined(_AFXDLL)
// Diagnostic Support
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
再來查看CCmdtarget的虛函數順序,在查看CObject的聲明文件後得到了這個類的虛函數順序:
DECLARE_DYNAMIC(CCmdTarget);
virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo);
#ifndef _AFX_NO_OLE_SUPPORT
// called when last OLE reference is released
virtual void OnFinalRelease();
#endif
#ifndef _AFX_NO_OLE_SUPPORT
// called before dispatching to an automation handler function
virtual BOOL IsInvokeAllowed(DISPID dispid);
virtual BOOL GetDispatchIID(IID* pIID);
virtual UINT GetTypeInfoCount();
virtual CTypeLibCache* GetTypeLibCache();
virtual HRESULT GetTypeLib(LCID lcid, LPTYPELIB* ppTypeLib);
之所以還要列出"DECLARE_DYNAMIC(CCmdTarget);"是因為這個宏的定義如下:
#define DECLARE_DYNAMIC(class_name) \
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static const AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
這個virtual CRuntimeClass* GetRuntimeClass() const; 覆蓋掉了一開始的CObject的相對應函數。依次按照類的順序對
照下來,就可以知道該表確實是虛函數表。同時,對應的GetMessageMap虛函數的位置上跟入後,可以得到如下代碼:
.text:00401010 ; *************** S U B R O U T I N E ***************************************
.text:00401010
.text:00401010
.text:00401010 sub_401010 proc near ; DATA XREF: .rdata:00402228o
.text:00401010 mov eax, offset off_4021C0
.text:00401015 retn
.text:00401015
.text:00401015 sub_401010 endp

恰恰是返回了我們之前假設的MessageMap的地址。

--------------------------------------------------------------------------------
【版權聲明】: 本文原創於看雪技術論壇, 轉載請註明作者並保持文章的完整, 謝謝!

D. 如何看c語言標准庫函數的源代碼

很遺憾,標准庫中的函數結合了系統,硬體等的綜合能力,是比較近機器的功能實現,所以大部分是用匯編完成的,而且已經導入到了lib和dll里了,就是說,他們已經被編譯好了,似乎沒有代碼的存在了.
能看到的也只有dll中有多少函數被共享.
第三方可能都是dll,因為上面也說了,dll是編譯好的,只能看到成品,就可以隱藏代碼,保護自己的知識產權,同時也是病毒的歸宿...... 當然,除了DLL的確還存在一種東西,插件程序~~~

E. 如何查看C語言,內庫的源代碼

一般情況下是不能打開的。
除非使用反匯編軟體。但是反匯編軟體效果不盡如人意,需要人工猜測的地方太多!
而且如果使用了先進的代碼模糊技術的話,基本上很難看透源代碼的用意。
正常情況下,建議問作者索要源代碼,如果作者的軟體是閉源軟體的話,如果不是大神並且時間不多,那麼「打開exe格式的c語言文件的源代碼」
基本上就是天方夜譚了。

F. C++標准類庫的原代碼在哪兒能找

SGI STL 是開源的,網上到處都是
安裝VC後,安裝目錄下就有其源碼

G. 在哪裡可以找到C語言標准庫的實現源代碼

Linux下的glic庫的源碼鏈接:
http://ftp.gnu.org/gnu/glibc/,你可以下載最新版本的glibc-2.24.tar.gz這個壓縮文件,在Windows系統下直接用WinRAR解壓即可,如果在Linux系統下用命令行解壓的話,命令如下:tar -xzvf glibc-2.24.tar.gz。

H. VC 6.0的C語言庫函數的源代碼可以在哪找到

深入printf
/***
*printf.c - print formatted
*
* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
* defines printf() - print formatted data
*
*******************************************************************************/

#include
#include
#include
#include
#include
#include
#include

/***
*int printf(format, ...) - print formatted data
*
*Purpose:
* Prints formatted data on stdout using the format string to
* format data and getting as many arguments as called for
* Uses temporary buffering to improve efficiency.
* _output does the real work here
*
*Entry:
* char *format - format string to control data format/number of arguments
* followed by list of arguments, number and type controlled by
* format string
*
*Exit:
* returns number of characters printed
*
*Exceptions:
*
*******************************************************************************/

int __cdecl printf (
const char *format,
...
)
/*
* stdout ''PRINT'', ''F''ormatted
*/
{
va_list arglist;
int buffing;
int retval;

va_start(arglist, format);

_ASSERTE(format != NULL);//斷言宏。如果輸出格式字元串指針為空,則在DEBUG版下斷言,報告錯誤。

_lock_str2(1, stdout);

buffing = _stbuf(stdout);//stdout:指定輸出到屏幕

retval = _output(stdout,format,arglist);

_ftbuf(buffing, stdout);

_unlock_str2(1, stdout);

return(retval);
}
以上為printf()的源代碼
1、從含有可選參數函數中獲得可選參數,以及操作這些參數
typedef char *va_list;
void va_start( va_list arg_ptr, prev_param );
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
假定函數含有一個必選參數和多個可選參數,必選參數聲明為普通數據類型,且能通過參數名來獲得該變數的值。可選參數通過宏va_start、va_arg和va_end(定義在stdarg.h或varargs.h中)來進行操作,即通過設置指向第一個可選參數指針、返回當前參數、在返回參數後重新設置指針來操作所有的可選參數。
va_start:為獲取可變數目參數的函數的參數提供一種便捷手段。設置arg_ptr為指向傳給函數參數列表中的第一個可選參數的指針,且該參數必須是va_list類型。prev_param是在參數列表中第一個可選參數前的必選參數。
va_arg:返回由arg_ptr所指向的參數的值,且自增指向下一個參數的地址。type為當前參數的類型,用來計算該參數的長度,確定下一個參數的起始位置。它可以在函數中應用多次,直到得到函數的所有參數為止,但必須在宏va_start後面調用。
va_end:在獲取所有的參數後,設置指針arg_ptr為NULL。
下面舉例說明:
#include
#include
int average( int first, ... );
void main( void )
{
/* Call with 3 integers (-1 is used as terminator). */
printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );

/* Call with 4 integers. */
printf( "Average is: %d\n", average( 5, 7, 9, 11, -1 ) );

/* Call with just -1 terminator. */
printf( "Average is: %d\n", average( -1 ) );
}

int average( int first, ... )
{
int count = 0, sum = 0, i = first;
va_list marker;

va_start( marker, first ); /* Initialize variable arguments. */
while( i != -1 )
{
sum += i;
count++;
i = va_arg( marker, int);
}
va_end( marker ); /* Reset variable arguments. */
return( sum ? (sum / count) : 0 );
}
返回值為:
Average is: 3
Average is: 8
Average is: 0
綜上所述,在printf()函數中,可以只輸出一個字元串,也可按照一定的形式輸出含有多個可選參數的字元串信息。因此,首先就要通過這些宏來獲取所有的可選參數。在上面的源碼可以看出printf()中,只使用了宏at_start,將可選參數的首地址賦給了arglist。
2、鎖定字元串及輸出字元串到屏幕
#define _lock_str2(i,s) _lock_file2(i,s)
void __cdecl _lock_file2(int, void *);
#define _unlock_str2(i,s) _unlock_file2(i,s)
void __cdecl _unlock_file2(int, void *);
int __cdecl _stbuf(FILE *);
void __cdecl _ftbuf(int, FILE *);
int __cdecl _output(FILE *, const char *, va_list);
在output函數中,讀取格式字元串中的每一個字元,然後對其進行處理,處理方式根據每一個字元所代表的意義來進行,如:普通字元直接利用函數WRITE_CHAR(ch, &charsout);輸出到控制台。
其中的主要部分是對轉換說明符(d,c,s,f)的處理,現在將對其中的部分代碼進行詳細說明,這里只說明最基本的轉換說明符,對這些須基本的轉換說明符進行修飾的修飾符,程序中單獨進行處理。下面是函數output()(output.c)部分源代碼:
case ST_TYPE:
//表示當前處理的字元的類型為轉換說明符。
...
switch (ch) {
//下面對參數的獲取都是利用宏va_arg( va_list arg_ptr, type );來進行的。
case ''c'': {
//從參數表中獲取單個字元,輸出到緩沖字元串中,此時,type=int
buffer[0] = (char) get_int_arg(&argptr); /* get char to print */
text = buffer;
textlen = 1; /* print just a single character */
}
break;

case ''s'': {
//從參數表中獲取字元串,輸出到緩沖字元串中,此時,type=char*
int i;
char *p; /* temps */
text = get_ptr_arg(&argptr);
...
}
break;

case ''w'': {
//對寬字元進行處理
...
} /* case ''w'' */
break;
...
case ''e'':
case ''f'':
case ''g'': {
//對浮點數進行操作
...
#if !LONGDOUBLE_IS_DOUBLE
/* do the conversion */
if (flags & FL_LONGDOUBLE) {
_cldcvt((LONGDOUBLE*)argptr, text, ch, precision, capexp);
va_arg(argptr, LONGDOUBLE);
//對長雙精度型進行處理,此時,type=long double
}
else
#endif /* !LONGDOUBLE_IS_DOUBLE */
{

//對雙精度型進行處理,此時,type=double
_cfltcvt((DOUBLE*)argptr, text, ch, precision, capexp);
va_arg(argptr, DOUBLE);
}
...
break;
//對整型變數處理
case ''d'':
case ''i'':
...
goto COMMON_INT;

case ''u'':
radix = 10;
goto COMMON_INT;

case ''p'':
...
goto COMMON_INT;

case ''o'':
...

註:對於浮點型double和long double,有相應的轉換說明符(%f表示雙精度型,%lf表示長雙精度型),而float卻沒有。其中的原因是,在K&RC下,float值用於表達式或用作參數前,會自動轉換成double類型。而ANSI C一般不會自動把float轉換成double。有些程序已假定其中的float參數會被轉換成double,為了保護大量這樣的程序,所有printf()函數的float參數還是被自動轉換成double型。因此,在K&RC或ANSI C下,都無需用特定的轉換說明符來顯示float型。
綜上所述,轉換說明符必須與待列印字元的類型。通常,用戶有種選擇。例如,如要列印一個int類型的值。則只可以使用%d,%x或%o。所有這些說明符都表示要列印一個int類型的值;它們只不過提供了一個數值的幾種不同表示。類似一,可以用%f、%g和%e來表示double類型的值。但如果轉換說明與類型不匹配,將會出現意想不到的結果。為什麼呢?問題就在於C向函數傳遞信息的方式。
這個失敗的根本細節與具體實現相關。它決定了系統中的參數以何方式傳遞。函數調用如下:
float n1;
double n2;
long n3;
long n4;
...
printf("%ld,%ld,%ld,%ld",n1,n2,n3,n4);
這個調用告訴計算機,要把變數n1,n2,n3和n4的值交給計算機,它把這些變數放進稱作棧(stack)的內存區域中,來完成這一任務。計算機把這些值放進棧中,其根據是變數的類型而不是轉換說明符,比如n1,把8個位元組放入棧中(float被轉換成double),類似地,為n2放了8位元組,其後給n3和n4各放了4個位元組。接著,控制的對象轉移到printf();此函數從棧中讀數,不過在這一過程中,它是在轉換說明符的指導下,讀取數值的。說明符%ld指定printf()應讀4個位元組(va_arg( va_list arg_ptr, type )中type=long),因此printf()讀入棧中的4個位元組,作為它的第一個值。但是這只是n1的前半部分,這個值被看成一個long整數。下一個說明符%ld讀入4個位元組,這正是n1的後半部分,這個值被看成第二個long整數。類似地,第三、第四次又讀入n2的前後兩部分。因此,盡管我們對n3和n4使用了正確的說明符,printf()仍然會產生錯誤。

這里也可以下載
http://mirrors.kernel.org/gnu/glibc/glibc-2.7.tar.gz

I. c庫函數源碼

不是你表達不清,也許只是你根本不想仔細看一睛VC下面目錄的源碼,事實上就是有的。後附其中的qsort.c,以證明所言不虛。

VC的庫是提供源碼的,這東西也不值錢。
X:\Program Files\Microsoft Visual Studio\VCXX\CRT\SRC
注意有些可能本身是用匯編寫的。

/***
*qsort.c - quicksort algorithm; qsort() library function for sorting arrays
*
* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
* To implement the qsort() routine for sorting arrays.
*
*******************************************************************************/

#include <cruntime.h>
#include <stdlib.h>
#include <search.h>

/* prototypes for local routines */
static void __cdecl shortsort(char *lo, char *hi, unsigned width,
int (__cdecl *comp)(const void *, const void *));
static void __cdecl swap(char *p, char *q, unsigned int width);

/* this parameter defines the cutoff between using quick sort and
insertion sort for arrays; arrays with lengths shorter or equal to the
below value use insertion sort */

#define CUTOFF 8 /* testing shows that this is good value */

/***
*qsort(base, num, wid, comp) - quicksort function for sorting arrays
*
*Purpose:
* quicksort the array of elements
* side effects: sorts in place
*
*Entry:
* char *base = pointer to base of array
* unsigned num = number of elements in the array
* unsigned width = width in bytes of each array element
* int (*comp)() = pointer to function returning analog of strcmp for
* strings, but supplied by user for comparing the array elements.
* it accepts 2 pointers to elements and returns neg if 1<2, 0 if
* 1=2, pos if 1>2.
*
*Exit:
* returns void
*
*Exceptions:
*
*******************************************************************************/

/* sort the array between lo and hi (inclusive) */

void __cdecl qsort (
void *base,
unsigned num,
unsigned width,
int (__cdecl *comp)(const void *, const void *)
)
{
char *lo, *hi; /* ends of sub-array currently sorting */
char *mid; /* points to middle of subarray */
char *loguy, *higuy; /* traveling pointers for partition step */
unsigned size; /* size of the sub-array */
char *lostk[30], *histk[30];
int stkptr; /* stack for saving sub-array to be processed */

/* Note: the number of stack entries required is no more than
1 + log2(size), so 30 is sufficient for any array */

if (num < 2 || width == 0)
return; /* nothing to do */

stkptr = 0; /* initialize stack */

lo = base;
hi = (char *)base + width * (num-1); /* initialize limits */

/* this entry point is for pseudo-recursion calling: setting
lo and hi and jumping to here is like recursion, but stkptr is
prserved, locals aren't, so we preserve stuff on the stack */
recurse:

size = (hi - lo) / width + 1; /* number of el's to sort */

/* below a certain size, it is faster to use a O(n^2) sorting method */
if (size <= CUTOFF) {
shortsort(lo, hi, width, comp);
}
else {
/* First we pick a partititioning element. The efficiency of the
algorithm demands that we find one that is approximately the
median of the values, but also that we select one fast. Using
the first one proces bad performace if the array is already
sorted, so we use the middle one, which would require a very
wierdly arranged array for worst case performance. Testing shows
that a median-of-three algorithm does not, in general, increase
performance. */

mid = lo + (size / 2) * width; /* find middle element */
swap(mid, lo, width); /* swap it to beginning of array */

/* We now wish to partition the array into three pieces, one
consisiting of elements <= partition element, one of elements
equal to the parition element, and one of element >= to it. This
is done below; comments indicate conditions established at every
step. */

loguy = lo;
higuy = hi + width;

/* Note that higuy decreases and loguy increases on every iteration,
so loop must terminate. */
for (;;) {
/* lo <= loguy < hi, lo < higuy <= hi + 1,
A[i] <= A[lo] for lo <= i <= loguy,
A[i] >= A[lo] for higuy <= i <= hi */

do {
loguy += width;
} while (loguy <= hi && comp(loguy, lo) <= 0);

/* lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy,
either loguy > hi or A[loguy] > A[lo] */

do {
higuy -= width;
} while (higuy > lo && comp(higuy, lo) >= 0);

/* lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi,
either higuy <= lo or A[higuy] < A[lo] */

if (higuy < loguy)
break;

/* if loguy > hi or higuy <= lo, then we would have exited, so
A[loguy] > A[lo], A[higuy] < A[lo],
loguy < hi, highy > lo */

swap(loguy, higuy, width);

/* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top
of loop is re-established */
}

/* A[i] >= A[lo] for higuy < i <= hi,
A[i] <= A[lo] for lo <= i < loguy,
higuy < loguy, lo <= higuy <= hi
implying:
A[i] >= A[lo] for loguy <= i <= hi,
A[i] <= A[lo] for lo <= i <= higuy,
A[i] = A[lo] for higuy < i < loguy */

swap(lo, higuy, width); /* put partition element in place */

/* OK, now we have the following:
A[i] >= A[higuy] for loguy <= i <= hi,
A[i] <= A[higuy] for lo <= i < higuy
A[i] = A[lo] for higuy <= i < loguy */

/* We've finished the partition, now we want to sort the subarrays
[lo, higuy-1] and [loguy, hi].
We do the smaller one first to minimize stack usage.
We only sort arrays of length 2 or more.*/

if ( higuy - 1 - lo >= hi - loguy ) {
if (lo + width < higuy) {
lostk[stkptr] = lo;
histk[stkptr] = higuy - width;
++stkptr;
} /* save big recursion for later */

if (loguy < hi) {
lo = loguy;
goto recurse; /* do small recursion */
}
}
else {
if (loguy < hi) {
lostk[stkptr] = loguy;
histk[stkptr] = hi;
++stkptr; /* save big recursion for later */
}

if (lo + width < higuy) {
hi = higuy - width;
goto recurse; /* do small recursion */
}
}
}

/* We have sorted the array, except for any pending sorts on the stack.
Check if there are any, and do them. */

--stkptr;
if (stkptr >= 0) {
lo = lostk[stkptr];
hi = histk[stkptr];
goto recurse; /* pop subarray from stack */
}
else
return; /* all subarrays done */
}

/***
*shortsort(hi, lo, width, comp) - insertion sort for sorting short arrays
*
*Purpose:
* sorts the sub-array of elements between lo and hi (inclusive)
* side effects: sorts in place
* assumes that lo < hi
*
*Entry:
* char *lo = pointer to low element to sort
* char *hi = pointer to high element to sort
* unsigned width = width in bytes of each array element
* int (*comp)() = pointer to function returning analog of strcmp for
* strings, but supplied by user for comparing the array elements.
* it accepts 2 pointers to elements and returns neg if 1<2, 0 if
* 1=2, pos if 1>2.
*
*Exit:
* returns void
*
*Exceptions:
*
*******************************************************************************/

static void __cdecl shortsort (
char *lo,
char *hi,
unsigned width,
int (__cdecl *comp)(const void *, const void *)
)
{
char *p, *max;

/* Note: in assertions below, i and j are alway inside original bound of
array to sort. */

while (hi > lo) {
/* A[i] <= A[j] for i <= j, j > hi */
max = lo;
for (p = lo+width; p <= hi; p += width) {
/* A[i] <= A[max] for lo <= i < p */
if (comp(p, max) > 0) {
max = p;
}
/* A[i] <= A[max] for lo <= i <= p */
}

/* A[i] <= A[max] for lo <= i <= hi */

swap(max, hi, width);

/* A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi */

hi -= width;

/* A[i] <= A[j] for i <= j, j > hi, loop top condition established */
}
/* A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j,
so array is sorted */
}

/***
*swap(a, b, width) - swap two elements
*
*Purpose:
* swaps the two array elements of size width
*
*Entry:
* char *a, *b = pointer to two elements to swap
* unsigned width = width in bytes of each array element
*
*Exit:
* returns void
*
*Exceptions:
*
*******************************************************************************/

static void __cdecl swap (
char *a,
char *b,
unsigned width
)
{
char tmp;

if ( a != b )
/* Do the swap one character at a time to avoid potential alignment
problems. */
while ( width-- ) {
tmp = *a;
*a++ = *b;
*b++ = tmp;
}
}

閱讀全文

與微軟c類庫的源碼相關的資料

熱點內容
c語言常用演算法pdf 瀏覽:960
編程如何讓畫面動起來 瀏覽:865
大齡女程序員未來發展 瀏覽:976
數學書籍pdf 瀏覽:506
加密門禁卡寫入成功無法開門 瀏覽:464
齒輪傳動pdf 瀏覽:52
alpinelinux 瀏覽:150
手機端app的掃碼功能在哪裡 瀏覽:227
少兒編程中小班英語教案 瀏覽:452
鎖屏密碼加密手機怎麼解除 瀏覽:205
linuxlostfound 瀏覽:135
征途伺服器ip地址 瀏覽:330
git提交代碼命令行 瀏覽:165
什麼叫瀏覽器伺服器結構 瀏覽:157
於謙聊天哪個app 瀏覽:449
小鵬汽車nlp演算法工程師薪資 瀏覽:881
代碼加密與隱藏 瀏覽:649
fordfulkerson演算法 瀏覽:352
京東熱app在哪裡可以下載 瀏覽:877
彩報圖書app哪個好 瀏覽:303