堆栈是一种先进后出的数据结构。是一种只允许在其一端进行插入或者删除的线性表。允许插入或删除操作的一端为栈顶,另一端称为栈底。对堆栈的插入和删除操作称为入栈和出栈。

1.1     概述

OpenSSL大量采用堆栈来存放数据。它实现了一个通用的堆栈,可以方便的存储任意数据。它实现了许多基本的堆栈操作,主要有:堆栈拷贝(sk_dup)、构建新堆栈(sk_new_null,sk_new)、插入数据(sk_insert)、删除数据(sk_delete)、查找数据(sk_find,sk_find_ex)、入栈(sk_push)、出栈(sk_pop)、获取堆栈元素个数(sk_num)、获取堆栈值(sk_value)、设置堆栈值(sk_set)和堆栈排序(sk_sort)。

1.2     堆栈相关结构描述

OpenSSL堆栈数据结构在crypto/stack/stack.h中定义,其详细定义如下:

typedef struct stack_st
{
int num;
char **data;
int sorted; int num_alloc;
int (*comp)(const void *, const void *);
} _STACK; /* Use STACK_OF(...) instead */

主要项意义如下:

num:int数据类型,堆栈中存放数据的个数。

data:char **数据类型,用于存放数据地址,每个数据地址存放在data[0]到data[num-1]中。

sorted:int数据类型,该堆栈是否排序,若已经排序,则为1,否则为0。堆栈数据一般是无序的,只有当用户调用了sk_sort操作,其值才为1。

num_alloc:int数据类型,分配内存的次数。

comp:回调函数,堆栈内存放数据的比较函数地址,此函数用于排序和查找操作;当用户生成一个新堆栈时,可以指定comp为用户实现的一个比较函数;或当堆栈已经存在时通过调用sk_set_cmp_func函数来重新指定比较函数。

1.3     堆栈相关函数

用户直接调用最底层的堆栈操作函数是一个麻烦的事情,对此openssl提供了用宏来帮助用户实现接口。用户可以参考safestack.h来定义自己的上层堆栈操作函数。openssl堆栈实现源码位于crypto/stack目录下。

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;
}

OpenSSL---堆栈的更多相关文章

  1. Openssl编程--源码分析

    Openssl编程 赵春平 著 Email: forxy@126.com 第一章 基础知识 8 1.1 对称算法 8 1.2 摘要算法 9 1.3 公钥算法 9 1.4 回调函数 11 第二章 ope ...

  2. OpenSSL编程

    简介 OpenSSL是一个功能丰富且自包含的开源安全工具箱.它提供的主要功能有:SSL协议实现(包括SSLv2.SSLv3和TLSv1).大量软算法(对称/非对称/摘要).大数运算.非对称算法密钥生成 ...

  3. openssl stack 数据结构栈基本操作

    堆栈是两种不同的数据结构: 堆:数据先进先出: 栈:数据先进后观: 在stack.h 中 openssl 为我们提供了一个通用的栈,利用提供的接口我们可以方便的用此栈来存放开发中的任意数据. open ...

  4. openssl知识点总结

    openssl知识点总结 实践总结见之前博客:http://www.cnblogs.com/Jclemo/p/6091201.html 简介 openssl是一个功能丰富且自包含的开源安全工具箱.它提 ...

  5. Centos7 编译安装 Nginx PHP Mariadb Memcached 扩展 ZendOpcache扩展 (实测 笔记 Centos 7.3 + Openssl 1.1.0e + Mariadb 10.1.22 + Nginx 1.12.0 + PHP 7.1.4 + Laravel 5.4 )

    环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G,双网卡) 系统版本:CentOS-7-x86_64-Minimal-1611.iso 安装步骤: 1.准备 1.0 查看硬 ...

  6. Openssl源代码整理学习---含P7/P10/P12说明

    声明:建议结合Openssl源代码学习: 一.基础知识 1.Openssl 简史 OpenSSL项目是加拿大人Eric A.Yang 和Tim J.Hudson开发,现在有Openssl项目小组负责改 ...

  7. Openssl源代码整理学习

    一.基础知识 1.Openssl 简史 OpenSSL项目是加拿大人Eric A.Yang 和Tim J.Hudson开发,现在有Openssl项目小组负责改进和维护:他们是全球一些技术精湛的志愿技术 ...

  8. 基于OpenSSL的RSA加密应用(非算法)

    基于OpenSSL的RSA加密应用(非算法) iOS开发中的小伙伴应该是经常用der和p12进行加密解密,而且在通常加密不止一种加密算法,还可以加点儿盐吧~本文章主要阐述的是在iOS中基于openSL ...

  9. openssl源码目录结构

    openssl源代码主要由eay库.ssl库.工具源码.范例源码以及测试源码组成. eay库是基础的库函数,提供了很多功能.源代码放在crypto目录下.包括如下内容: 1) asn.1 DER编码解 ...

随机推荐

  1. Apache BeanUtils 1.9.2 官方入门文档

    为什么需要Apache BeanUtils? Apache BeanUtils 是 Apache开源软件组织下面的一个项目,被广泛使用于Spring.Struts.Hibernate等框架,有数千个j ...

  2. hdu3306 Another kind of Fibonacci【矩阵快速幂】

    转载请注明出处:http://www.cnblogs.com/KirisameMarisa/p/4187670.html 题目链接:http://acm.hdu.edu.cn/showproblem. ...

  3. load、save方法、spark sql的几种数据源

    load.save方法的用法          DataFrame usersDF = sqlContext.read().load("hdfs://spark1:9000/users.pa ...

  4. grub2的/etc/default/grub文件详解

    # If you change this file, run 'update-grub' afterwards to update# /boot/grub/grub.cfg.GRUB_DEFAULT= ...

  5. PHP学习笔记8-文件操作

    在data文件中写入数据: <?php /** * Created by PhpStorm. * User: Administrator * Date: 2015/6/29 * Time: 17 ...

  6. [转]TOMCAT原理以及处理HTTP请求的过程、ContextPath ServletPath

    一.TOMCAT 1 - Tomcat Server的组成部分 <Server>     <Service>         <Connector/>        ...

  7. ZOJ 1893 A Multiplication Game 【简单博弈】

    感觉ZJU上有不少博弈的题目. 这道题目还是比较好理解的,题目大概意思是:两人轮流乘一个2-9的数,从1开始乘,求谁的乘积先大于N. 还是寻找必败点必胜点,不过在这个题目里转换成了寻找必败区间必胜区间 ...

  8. 原生弹窗拖拽代码demo+简单的抽奖

    拖拽效果 效果: 代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...

  9. Visual Studio 2015编译安装配置QT5.5.1(含QTWEBKIT)

    尽管QT5.5.1和VisualStudio 2015都已经发布很久了,但是QT项目组视乎不会为QT5.5.1专门发布预编译的QT5.5.1 for windows(2015)版本的,也不会专门发布V ...

  10. jQuery 遍历ul li 添加 移除

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...