?? c++編程思想 -- 第2章 筆記(2).txt
字號:
作者:rick1126
email: rickzhang@sina.com
日期:2001-7-17 10:19:32
2.2 一個袖珍C庫
【C函數庫的數據封裝方式】
. struct 用于處理一組特性
. C庫 一組struct + 一組活動在這些struct上的函數
【一個變長數組模擬的例子】
. 涉及操作:
- 使用一個結構保存數據, 附加一組操作維護數據
- C對于內存的分配和使用及其為維護
- 動態連接庫的導出
. 相關代碼
//stash.h
#if!defined(STASH_H)
#define STASH_H
typedef struct STASHtag{
int size; //每一個元素的大小
int quantity; //索引總長
int next; //下一個索引
unsigned char *storage; //數值指針, 動態分配
}Stash;
extern "C" {
void WINAPI initialize( Stash* S, int Size );
void WINAPI cleanup( Stash* S );
int WINAPI add ( Stash* S, void* element );
void* WINAPI fetch( Stash* S, int index );
int WINAPI count( Stash* S );
void WINAPI inflate( Stash* s, int increase );
}
#endif//STASH_H
; ch2_stash.def : Declares the module parameters for the DLL.
LIBRARY "ch2_stash"
DESCRIPTION 'ch2_stash Windows Dynamic Link Library'
EXPORTS
initialize
cleanup
add
fetch
count
inflate
; Explicit exports can go here
===>
1) 有關結構
- 使用XXXTag或者tagXXX進行typedef
- 使用US_XXX, *PUS_XXX定義實際的結構名稱和結構指針名稱
* 當然都是從一位長期從事C編程的同事那里獲得的經驗 ^_^
2) 有關導出的函數
- 使用extern "C" 返回類型 WINAPI 函數名( ... )進行聲明
- 相關的函數導出方式
==> 使用.DEF文件
在聲明使用 WINAPI, extern "C" 表示使用C執行方式, 考慮到兼容性
在DEF文件的EXPORTS段導出這些函數
==> __declspec(dllexport) 導出數據, 函數, 類或者類成員函數
函數例子:
//導出函數
__declspec(dllexport) void __cdecl Function1(void);
//導出一個類中的接口--公共成員
class __declspec(dllexport) CExampleExport : public CObject
{ ... class definition ... };
通常使用宏定義給出一個好用的預定義
#define DllExport __declspec( dllexport )
將函數名稱存儲在DLL的導出列表中, 如果你要優化該表格的大小, 使用.DEF文件方式.
//stash.cpp
#include "stdafx.h"
#include "stash.h"
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include "assert.h"
//描述: 初始化變長數組
void WINAPI initialize( Stash* S, int Size )
{
S->size = Size;
S->quantity = 0;
S->storage = 0;
S->next = 0;
}
//描述: 清空編程數組
void WINAPI cleanup( Stash* S )
{
if ( S->storage ){
puts( "free storage" );
free( S->storage );
}
}
//描述: 添加元素到變長數組
int WINAPI add ( Stash* S, void* element )
{
if ( S->next >= S->quantity )
inflate( S, 100 );
memcpy( &( S->storage[ S->next * S->size ] ), element, S->size );
S->next ++;
return ( S->next - 1 );
}
//描述: 獲得指定索引的數組元素
void* WINAPI fetch( Stash* S, int index )
{
if ( index >= S->next || index < 0 )
return 0;
return &( S->storage[index * S->size ] );
}
//描述: 變長數組計數
int WINAPI count( Stash* S )
{
return S->next;
}
//描述: 數組變長
void WINAPI inflate( Stash* S, int increase )
{
void* v=realloc( S->storage, ( S->quantity + increase ) * S->size );
assert(v);
S->storage = (unsigned char*)v;
S->quantity += increase;
}
==>
1) 函數實現
- 其實這個函數主要使用一個連續的緩沖區和定長的間隔存放指定的元素, 整個庫維護一個結構
2) 相關的概念
- C的內存分配(局部)函數
函數名稱 用途
-----------------------------------------------------------------------------
_alloca 從數據棧分配內存
calloc 為數組分配緩存, 初始化每一個字節為0
_calloc_dbg 調試版本下的 calloc
_expand 在不移動的前提下擴展縮小內存
_expand_dbg 調試版本下的 _expand
free 釋放內存
_free_dbg 調試版本下的 _free
_get_sbh_threshold 返回申請上限
_heapadd 添加內存到堆
_heapchk 檢測堆的連續性
_heapmin 釋放堆中的空閑內存
_heapset 使用指定值填充堆內存入口
_heapwalk 返回堆中的每一個入口的信息
malloc 從堆分配內存
_malloc_dbg 調試版本下的 malloc
_msize 返回申請內存塊的大小
_msize_dbg 調試版本下的 _msize
_query_new_handler 返回當前子函數句柄的地址, 子函數由 _set_new_handler 設置
_query_new_mode _set_new_mode 的句柄模式
realloc 重新申請內存塊新的大小
_realloc_dbg 調試版本下的 realloc
_set_new_handler 使得錯誤處理機制在 new 操作失敗的時候使能并且使能 STL 庫
_set_new_mode 設置 malloc 的新的句柄模式
_set_sbh_threshold 設置內存分配上限
// client.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "iostream.h"
#include "assert.h"
#include "windows.h"
#include "../stash.h"
#define BUFSIZE 80
int main(int argc, char* argv[])
{
Stash intStash, stringStash;
int i;
FILE *file;
char buf[BUFSIZE];
char* cp;
initialize( &intStash, sizeof(int) );
for ( i=0; i<100; i++ )
add( &intStash,&i );
initialize( &stringStash, sizeof(char)*BUFSIZE );
file = fopen( "..\\readme.txt", "r" );
assert( file );
while ( fgets( buf, BUFSIZE, file ) )
add( &stringStash, buf );
fclose( file );
for ( i=0; i<count( &intStash); i++ )
cout << (int)fetch( &intStash, i ) << endl;
i=0;
while ( ( cp = (char*)fetch( &stringStash, i++ ) )!=0 )
cout << (char*)fetch( &stringStash, i-1 ) << endl;
cleanup( &intStash );
cleanup( &stringStash );
return 0;
}
==> 客戶端應用程序
1) void* 的含義
通過類型轉換, void* 可以轉換任何標準數據類型, 由此該變長數組可以不拘一格的支持相應的數據類型, 只是類型檢查和轉換的工作由客戶端支持
〖個人理解〗
這里用到一個一些C里面的如何建立函數庫, 使用函數庫和相應的內存以及建庫的常用技巧. 特別是內存管理, 有了一個堆的概念. 堆用于申請一個連續內存, 然后提供應用程序的動態內存分配函數申請堆內的內存, 同時應用程序需要維護堆內部的內存管理.
在C++特別是VC里面, 傳統的內存分配函數已經為new/delete代替, 而且也無需先申請一個堆. 不過如果開發COM還是會發現一些傳統內存分配函數的影子, 畢竟從兼容性考慮, 2#標準的COM還是需要偏向或者生成C兼容的中間產物或者結果的.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -