OpenSSL---堆棧

堆棧是一種先進後出的數據結構。是一種只容許在其一端進行插入或者刪除的線性表。容許插入或刪除操做的一端爲棧頂,另外一端稱爲棧底。對堆棧的插入和刪除操做稱爲入棧和出棧。數據結構

1.1     概述

OpenSSL大量採用堆棧來存放數據。它實現了一個通用的堆棧,能夠方便的存儲任意數據。它實現了許多基本的堆棧操做,主要有:堆棧拷貝(sk_dup)、構建新堆棧(sk_new_nullsk_new)、插入數據(sk_insert)、刪除數據(sk_delete)、查找數據(sk_findsk_find_ex)、入棧(sk_push)、出棧(sk_pop)、獲取堆棧元素個數(sk_num)、獲取堆棧值(sk_value)、設置堆棧值(sk_set)和堆棧排序(sk_sort)。函數

1.2     堆棧相關結構描述

OpenSSL堆棧數據結構在crypto/stack/stack.h中定義,其詳細定義以下:spa

typedef struct stack_st
{
int num;
char **data;
int sorted;

int num_alloc;
int (*comp)(const void *, const void *);
} _STACK;  /* Use STACK_OF(...) instead */


主要項意義以下:指針

numint數據類型,堆棧中存放數據的個數。code

datachar **數據類型,用於存放數據地址,每一個數據地址存放在data[0]data[num-1]中。對象

sortedint數據類型,該堆棧是否排序,若已經排序,則爲1,不然爲0。堆棧數據通常是無序的,只有當用戶調用了sk_sort操做,其值才爲1排序

num_allocint數據類型,分配內存的次數。接口

comp:回調函數,堆棧內存放數據的比較函數地址,此函數用於排序和查找操做;當用戶生成一個新堆棧時,能夠指定comp爲用戶實現的一個比較函數;或當堆棧已經存在時經過調用sk_set_cmp_func函數來從新指定比較函數。內存

1.3     堆棧相關函數

用戶直接調用最底層的堆棧操做函數是一個麻煩的事情,對此openssl提供了用宏來幫助用戶實現接口。用戶能夠參考safestack.h來定義本身的上層堆棧操做函數。openssl堆棧實現源碼位於crypto/stack目錄下。ssl

1.3.1    新建一個堆棧對象函數sk_new_null

函數功能:新建一個堆棧對象_STACK。該函數直接調用sk_new函數,參數直接傳的是(int (*)(const void *, const void *))0

函數定義:

_STACK *sk_new_null(void);

參數說明:

無。

返回值:若堆棧對象_STACK新建成功,則直接返回堆棧對象_STACK的指針。不然返回NULL

1.3.2    根據對象比較函數來建立一個堆棧對象函數sk_new

函數功能:根據對象比較函數來建立一個堆棧對象_STACK。該函數首先調用OPENSSL_malloc函數給對象分配內存,而後給每一個對象分配相對應的內存。注意:數據地址首先分配的是4個。

函數定義:

_STACK *sk_new(int (*cmp)(constvoid *, const void *));


參數說明:

cmp[in]回調函數,對象的比較函數。

返回值:若堆棧對象_STACK新建成功,則直接返回堆棧對象_STACK的指針。不然返回NULL

1.3.3    釋放堆棧本身的內存空間函數sk_free

函數功能:釋放堆棧本身的內存空間函數。該函數首先調用OPENSSL_free函數釋放掉數據地址,而後再調用OPENSSL_free函數釋放掉堆棧對象自己。

函數定義:

void sk_free(_STACK *st);


參數說明:

st[in] _STACK *數據類型,須要釋放的堆棧對象。

返回值:無。

1.3.4    釋放堆棧內存放的數據以及堆棧自己的函數sk_pop_free

函數功能:本函數用於釋放堆棧內存放的數據以及堆棧自己,它須要一個由用戶指定的針對具體數據的釋放函數。若是用戶僅調用sk_free函數,則只會釋放堆棧自己所用的內存,而不會釋放數據內存。

函數定義:

void sk_pop_free(_STACK *st,void (*func)(void *));


參數說明:

st[in] _STACK *數據類型,須要釋放的堆棧對象。

func[in]對象的釋放函數。

返回值:無。

1.3.5    向堆棧中插入數據函數sk_insert

函數功能:根據指定的位置往堆棧對象中插入數據。該函數首先判斷堆棧對象是否須要分配內存空間,若須要,則分配內存空間。而後將數據添加到指定的位置。

函數定義:

int sk_insert(_STACK *sk, void *data, int where);


參數說明:

sk[in] _STACK *數據類型,須要添加數據的堆棧對象。

data[in] void *數據類型,須要添加的數據。

where[in] int數據類型,須要插入的位置。

返回值:返回堆棧對象中數據的個數。

1.3.6    刪除指定位置的堆棧對象函數sk_delete

函數功能:刪除指定位置的堆棧對象。該函數首先判斷須要刪除數據的位置是否合法,若不合法,則返回。而後循環移位賦值。

函數定義:

void *sk_delete(_STACK *st,int loc);


參數說明:

sk[in] _STACK *數據類型,須要刪除數據的堆棧對象。

loc[in] int數據類型,須要刪除的位置。

返回值:若刪除成功,則直接返回刪除的堆棧數據。不然返回NULL

1.3.7    從堆棧對象中刪除指定的對象值函數sk_delete_ptr

函數功能:從堆棧對象中刪除指定的對象值。該函數首先遍歷整個堆棧對象中的對象值,判斷每一個堆棧對象值是否與須要刪除的對象值相等,若相等,則刪除,並返回值。

函數定義:

void *sk_delete_ptr(_STACK *st,void *p);


參數說明:

sk[in] _STACK *數據類型,須要刪除數據的堆棧對象。

p[in] void *數據類型,須要刪除的對象值。

返回值:若堆棧對象中有須要刪除的值,則返回刪除成功後的值;若沒有,則直接返回NULL

1.3.8    根據對象值從堆棧中查找它的位置函數sk_find

函數功能:根據數據地址來查找它在堆棧中的位置。當堆棧設置了比較函數時,它首先對堆棧進行排序,而後經過二分法進行查找。若是堆棧沒有設置比較函數,它只是簡單的比較數據地址來查找。

函數定義:

int sk_find(_STACK *st,void *data);


參數說明:

sk[in] _STACK *數據類型,須要查找數據的堆棧對象。

p[in] void *數據類型,須要查找的對象值。

返回值:若堆棧中有該對象,則返回它的位置,不然返回-1

1.3.9    根據對象值從堆棧中查找它的位置函數sk_find_ex

函數功能:根據數據地址來查找它在堆棧中的位置。當堆棧設置了比較函數時,它首先對堆棧進行排序,而後經過二分法進行查找。若是堆棧沒有設置比較函數,它只是簡單的比較數據地址來查找。

函數定義:

int sk_find_ex(_STACK *st,void *data);


參數說明:

sk[in] _STACK *數據類型,須要查找數據的堆棧對象。

p[in] void *數據類型,須要查找的對象值。

返回值:若堆棧中有該對象,則返回它的位置,不然返回-1

1.3.10 向堆棧棧頂插入數據函數sk_push

函數功能:向堆棧棧頂插入數據。該函數實際上調用的是sk_insert函數,最後一個參數傳的是st->num

函數定義:

int sk_push(_STACK *st,void *data);


參數說明:

sk[in] _STACK *數據類型,須要添加數據的堆棧對象。

data[in] void *數據類型,須要添加的數據。

返回值:返回堆棧對象中數據的個數。

1.3.11 往堆棧棧底插入數據函數sk_unshift

函數功能:往堆棧棧底插入一條數據。該函數實際上調用的是sk_insert函數,最後一個參數傳的是0

函數定義:

int sk_unshift(_STACK *st,void *data);


參數說明:

sk[in] _STACK *數據類型,須要添加數據的堆棧對象。

data[in] void *數據類型,須要添加的數據。

返回值:返回堆棧對象中數據的個數。

1.3.12 刪除棧底的數據函數sk_shift

函數功能:刪除棧底的數據。該函數實際上調用的是sk_delete函數,第二個參數傳的是0

函數定義:

void *sk_shift(_STACK *st);


參數說明:

sk[in] _STACK *數據類型,須要刪除數據的堆棧對象。

返回值:若刪除成功,則直接返回刪除的堆棧數據。不然返回NULL

1.3.13 刪除棧頂的數據函數sk_pop

函數功能:刪除棧頂的數據。該函數實際上調用的是sk_delete函數,第二個參數傳的是st->num - 1

函數定義:

void *sk_shift(_STACK *st);


參數說明:

sk[in] _STACK *數據類型,須要刪除數據的堆棧對象。

返回值:若刪除成功,則直接返回刪除的堆棧數據。不然返回NULL

1.3.14 初始化堆棧對象的數據值的函數sk_zero

函數功能:初始化堆棧對象的數據值。該函數直接調用memset函數來初始化堆棧對象的數據值。

函數定義:

void sk_zero(_STACK *st);


參數說明:

sk[in] _STACK *數據類型,須要初始化的堆棧對象。

返回值:無。

1.3.15 設置堆棧存放數據的比較函數sk_set_cmp_func

函數功能:設置堆棧存放數據的比較函數。因爲堆棧不知道用戶存放的是什麼數據,因此,比較函數必須由用戶本身實現。

函數定義:

int (*sk_set_cmp_func(_STACK *sk,int (*c)(const void *, const void *)))
(const void *, const void *);

參數說明:

sk[in] _STACK *數據類型,須要設置比較函數的堆棧對象。

c:比較函數。

返回值:若設置成功,則返回比較函數。不然返回原來的比較函數。

1.3.16 堆棧對象的複製函數sk_dup

函數功能:複製一個堆棧對象。該函數首先聲明一個堆棧對象,而後將須要複製的堆棧對象逐個賦值。

函數定義:

_STACK *sk_dup(_STACK *st);


參數說明:

sk[in] _STACK *數據類型,須要複製的堆棧對象。

返回值:若複製成功,則返回堆棧對象指針,不然返回NULL

1.3.17 對堆棧數據排序函數sk_sort

函數功能:對堆棧中的數據進行排序。它首先根據sorted來判斷是否已經排序,若是未排序則調用了標準C函數qsort進行快速排序。

函數定義:

void sk_sort(_STACK *st);


參數說明:

sk[in] _STACK *數據類型,須要排序的堆棧對象。

返回值:無。

1.3.18 獲取堆棧對象中的排序標識函數sk_is_sorted

函數功能:獲取堆棧對象中的排序標識。

函數定義:

int sk_is_sorted(const _STACK *st);


參數說明:

sk[in] const _STACK *數據類型,須要獲取值的堆棧對象。

返回值:堆棧對象排序標識。

1.3.19 獲取堆棧對象中的數據的總數函數sk_num

函數功能:獲取堆棧對象中的數據的總數。

函數定義:

int sk_num(const _STACK *st );


參數說明:

sk[in] const _STACK *數據類型,須要獲取值的堆棧對象。

返回值:堆棧對象中的數據的總數。

1.3.20 獲取指定位置的堆棧對象中的數據函數sk_value

函數功能:獲取指定位置的堆棧對象中的數據。

函數定義:

void *sk_value(const _STACK *st,int i);


參數說明:

sk[in] const _STACK *數據類型,須要獲取值的堆棧對象。

i[in] int數據類型,指定位置。

返回值:堆棧對象中的數據值指針。

1.4     應用實例

本實例中,首先聲明一個people_info_st對象,而後利用宏定義來操做底層的堆棧處理函數。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/safestack.h>
#include <openssl/crypto.h>

#define sk_PEOPLE_INFO_new(cmp)                                                     SKM_sk_new(PEOPLE_INFO, (cmp))
#define sk_PEOPLE_INFO_new_null()                                           SKM_sk_new_null(PEOPLE_INFO)
#define sk_PEOPLE_INFO_free(st)                                                SKM_sk_free(PEOPLE_INFO, (st))
#define sk_PEOPLE_INFO_num(st)                                                SKM_sk_num(PEOPLE_INFO, (st))
#define sk_PEOPLE_INFO_value(st, i)                                           SKM_sk_value(PEOPLE_INFO, (st), (i))
#define sk_PEOPLE_INFO_set(st, i, val)                               SKM_sk_set(PEOPLE_INFO, (st), (i), (val))
#define sk_PEOPLE_INFO_zero(st)                                                SKM_sk_zero(PEOPLE_INFO, (st))
#define sk_PEOPLE_INFO_push(st, val)                               SKM_sk_push(PEOPLE_INFO, (st), (val))
#define sk_PEOPLE_INFO_unshift(st, val)                                     SKM_sk_unshift(PEOPLE_INFO, (st), (val))
#define sk_PEOPLE_INFO_find(st, val)                                 SKM_sk_find(PEOPLE_INFO, (st), (val))
#define sk_PEOPLE_INFO_delete(st, i)                                SKM_sk_delete(PEOPLE_INFO, (st), (i))
#define sk_PEOPLE_INFO_delete_ptr(st, ptr)                      SKM_sk_delete_ptr(PEOPLE_INFO, (st), (ptr))
#define sk_PEOPLE_INFO_insert(st, val, i)                           SKM_sk_insert(PEOPLE_INFO, (st), (val), (i))
#define sk_PEOPLE_INFO_set_cmp_func(st, cmp)              SKM_sk_set_cmp_func(PEOPLE_INFO, (st), (cmp))
#define sk_PEOPLE_INFO_dup(st)                                                 SKM_sk_dup(PEOPLE_INFO, st)
#define sk_PEOPLE_INFO_pop_free(st, free_func)             SKM_sk_pop_free(PEOPLE_INFO, (st), (free_func))
#define sk_PEOPLE_INFO_shift(st)                                      SKM_sk_shift(PEOPLE_INFO, (st))
#define sk_PEOPLE_INFO_pop(st)                                                 SKM_sk_pop(PEOPLE_INFO, (st))
#define sk_PEOPLE_INFO_sort(st)                                                 SKM_sk_sort(PEOPLE_INFO, (st))

typedef struct people_info_st
{
char       *name, *otherInfo;
int        age;
}PEOPLE_INFO;

PEOPLE_INFO *PEOPLE_INFO_Malloc()
{
PEOPLE_INFO *a= ( PEOPLE_INFO * )OPENSSL_malloc(sizeof(PEOPLE_INFO));

a->name = ( char * )OPENSSL_malloc(20);
strcpy( a->name, "zcp" );
a->otherInfo = ( char * )OPENSSL_malloc(20);
strcpy( a->otherInfo, "no info" );
a->age = 20;

return a;
}

void PEOPLE_INFO_Free( PEOPLE_INFO *a )
{
OPENSSL_free( a->name );
OPENSSL_free( a->otherInfo );
OPENSSL_free( a );
}

static int PEOPLE_INFO_cmp( const PEOPLE_INFO *const *a, const PEOPLE_INFO *const *b )
{
int ret;
/* 只比較關鍵字 */
ret = strcmp(  (*a)->name, (*b)->name );

return ret;
}

int main( int argc, char *argv[] )
{
STACK_OF(PEOPLE_INFO)      *s,*snew;
PEOPLE_INFO          *s1,*one,*s2;
int                  i, num;

/* 新建一個堆棧對象 */
s = sk_PEOPLE_INFO_new_null();

/* 新建一個堆棧對象 */
snew = sk_PEOPLE_INFO_new( PEOPLE_INFO_cmp );

s2 = PEOPLE_INFO_Malloc();

sk_PEOPLE_INFO_push( snew, s2 );
i=sk_PEOPLE_INFO_find( snew, s2 );
s1 = PEOPLE_INFO_Malloc();
sk_PEOPLE_INFO_push( s, s1 );

num = sk_PEOPLE_INFO_num( s );

for( i = 0;i< num; i++ )
{
          printf("堆棧s中的數據有:\n" );
           one = sk_PEOPLE_INFO_value( s, i );
           printf("PEOPLE_INFO name :    %s\n",one->name );
           printf("PEOPLE_INFO age  :     %d\n",one->age );
          printf("PEOPLE_INFO otherinfo :      %s\n\n\n",one->otherInfo );
           printf("\n\n");
}

for( i = 0;i< num; i++ )
{
           printf("堆棧snew中的數據有:\n" );
           one = sk_PEOPLE_INFO_value( snew, i );
           printf("PEOPLE_INFO name :    %s\n",one->name );
           printf("PEOPLE_INFO age  :     %d\n",one->age );
           printf("PEOPLE_INFO otherinfo :      %s\n\n\n",one->otherInfo );
           printf("\n\n");
}
sk_PEOPLE_INFO_pop_free( s, PEOPLE_INFO_Free );
sk_PEOPLE_INFO_pop_free( snew, PEOPLE_INFO_Free );

return 0;
}
相關文章
相關標籤/搜索