OpenSSL学习笔记——堆栈

本文介绍了OpenSSL中堆栈(STACK)的数据结构及其常用操作函数,包括栈的定义、复制、创建、插入、删除等。同时,文章强调了使用宏定义进行栈操作的重要性,以确保数据类型的正确性和安全性。
摘要由CSDN通过智能技术生成

环境:OpenSSL 0.9.8l,Fedora 12

  

  今天学的是《OpenSSL编程》第3章 堆栈。这一章讲了OpenSSL中堆栈的用法,OpenSSL实现了一个通用的栈,这个栈可以存储所有的数据类型(因为栈里存的是地址)。

  下面是这章中最重要的一个数据结构,STACK,这个数据结构定义在文件stack.h里:

  typedef struct stack_st
  {
 
    int num;     
//已经进栈的元素的个数
    char **data;              
//栈的起始地址
 
    int sorted;              
  //如果栈已排过序,则为1;否则为0
 
    int num_alloc;       
  //栈的总大小
 
    int (*comp)(const char * const *, const char * const *); 
//在排序时使用的比较函数,由用户指定
 
  
} STACK;

  下面是与栈操作相关的几个操作函数,在文件stack.h里声明,在文件stack.c里实现:

  1. int (*sk_set_cmp_func(STACK *sk, int (*c)(const char * const *,const char *     const *)))

      (const char * const *, const char * const *)

    这 个函数需要的参数是一个栈的指针,和一个函数指针,返回值也是一个函数指针。此函数的作用是给一个栈设定一个比较函数,并返回以前的比较函数,也就是说把 参数c赋给sk->comp,并返回以前的sk->comp。如果c和以前的sk->comp不是同一个函数,则把 sk->sorted赋为0。

  2. STACK *sk_dup(STACK *sk)

   此函数的作用是将sk指向的栈的内容复制到一个新栈中,如果成功则返回新的栈的地址,否则返回NULL。

  3. STACK *sk_new_null(void)

   此函数的作用是产生一个新的栈,并且不设定栈的比较函数,返回新栈的地址,该函数是通过函数sk_new实现的(return sk_new((int (*)(const char * const *, const char * const *))0);)。

  4. STACK *sk_new(int (*c)(const char * const *, const char * const *))

    此函数的作用是产生一个新栈,参数是比较函数的函数指针,此函数会为该栈预先产生MIN_NODES个sizeof(char *)的数组,并把数组首地址赋给data,然后把num的值设为0,把num_alloc的值设为MIN_NODES,把comp为值设为c,把 sorted的值设为0。如果函数执行过程中没有问题,则最后返回新的栈的指针;如果出错,则返回NULL。

  5. int sk_insert(STACK *st, char *data, int loc)

   此函数的作用是把data的值插入栈的第loc个元素的地方,如果成功,返回目前栈中元素的总个数,否则返回0。不过在这个函数的定义里有一点比较奇怪:

   #ifdef undef  /* no memmove on sunos :-( */
       memmove( (char *)&(st->data[loc+1]),
       (char *)&(st->data[loc]),
       sizeof(char *)*(st->num-loc));
    #endif

这样来注释一段语句的,还是头一回见。

  6. char *sk_delete_ptr(STACK *st, char *p)

   此函数的作用是从栈st中移除值为p的一项,成功则返回p,失败则返回NULL。此函数通过函数sk_delete实现。

  7. char *sk_delete(STACK *st, int loc)

   此函数的作用是从栈st中移除第loc个元素,成功则返回第loc个元素的内容,失败则返回NULL。

  8. static int internal_find(STACK *st, char *data, int ret_val_options)

    此函数是一个内部函数,不能被外部程序使用,而函数sk_find和函数sk_find_ex都是通过此函数实现的。此函数的作用是在st中查找 data,若找到则返回下标,否则返回-1。如果st没有设定比较函数,则在栈中查找与data的值一样的元素;如果st设定了比较函数,则以比较函数为 参数调用OBJ_bsearch_ex来查找,若找到则返回下标,否则返回-1。

  9. int sk_find(STACK *st, char *data)

    OBJ_BSEARCH_FIRST_VALUE_ON_MATCH的字面意思来看,这个函数的意思是找第一个匹配的元素

    int sk_find(STACK *st, char *data)

   {
    return internal_find(st, data, OBJ_BSEARCH_FIRST_VALUE_ON_MATCH);
   }

  10. int sk_find_ex(STACK *st, char *data)
   
{
    return internal_find(st, data, OBJ_BSEARCH_VALUE_ON_NOMATCH);
   }

  11. int sk_push(STACK *st, char *data)

   此函数的作用是将data进栈,也就是把data插入到栈的最后:

   int sk_push(STACK *st, char *data)
   {
    
return(sk_insert(st,data,st->num));
   }

  12. int sk_unshift(STACK *st, char *data)

   此函数的作用是在栈底插入一个元素。

    int sk_unshift(STACK *st, char *data)
   {
    return(sk_insert(st,data,0));
   }

  13. char *sk_shift(STACK *st)

    此函数的作用是从栈底删除一个元素。

   char *sk_shift(STACK *st)
   {
    if (st == NULL) return(NULL);
    if (st->num <= 0) return(NULL);
    return(sk_delete(st,0));
   }

  14. char *sk_pop(STACK *st)

   此函数的作用是从栈st中出栈一个元素:

   char *sk_pop(STACK *st)
   {
    if (st == NULL) return(NULL);
    if (st->num <= 0) return(NULL);
    return(sk_delete(st,st->num-1));
   }

  15. void sk_zero(STACK *st)

   此函数的作用是将栈中所有元素清0。

    void sk_zero(STACK *st)
   {
    if (st == NULL) return;
    if (st->num <= 0) return;
    memset((char *)st->data,0,sizeof(st->data)*st->num);
    st->num=0;
   }

  16. void sk_pop_free(STACK *st, void (*func)(void *))

   此函数的作用是对栈中每个元素做func的操作,然后销毁栈。func可以是元素的清除函数。

   void sk_pop_free(STACK *st, void (*func)(void *))
   {
    int i;

    if (st == NULL) return;
    for (i=0; i<st->num; i++)
     if (st->data[i] != NULL)
      func(st->data[i]);
    sk_free(st);
   }

  17. void sk_free(STACK *st)

   此函数的作用是释放栈所占的内存空间。

    void sk_free(STACK *st)
   {
    if (st == NULL) return;
    if (st->data != NULL) OPENSSL_free(st->data);
    OPENSSL_free(st);
   }

  18. int sk_num(const STACK *st)

   此函数的作用是返回栈中元素的个数。

  19. char *sk_value(const STACK *st, int i)

   此函数的作用是获取栈中第i个元素的值。

    char *sk_value(const STACK *st, int i)
   {
    if(!st || (i < 0) || (i >= st->num)) return NULL;
    return st->data[i];
   }

  20. char *sk_set(STACK *st, int i, char *value)

   此函数的作用是把栈中第i个元素的值改为value。

   char *sk_set(STACK *st, int i, char *value)
   {
    if(!st || (i < 0) || (i >= st->num)) return NULL;
    return (st->data[i] = value);
   }

  21. void sk_sort(STACK *st)

    此函数的作用是给栈中的元素排序,排序算法是qsort,使用的比较函数是st->comp,排完序以后,把st->sorted设为1。需要注意的是,如果没有给栈指定比较函数,而调用此函数,会产生段错误。

  22. int sk_is_sorted(const STACK *st)
    
{
      if (!st)
       return 1;
      return st->sorted;
     }

 

  上面是栈的操作函数,但是OpenSSL不建议我们直接去用这些函数来操作我们的栈和栈中的数据,而是建议我们去定义自己的宏来间接调用这些函数。

  对于下面的例子,假设栈中保存的元素是指向结构体Student的指针,结构体Student定义如下:

  typedef struct Student_st
  {
   char *name;
   int age;
   char *otherInfo;
  }Student;

  如果我们要使用sk_new新建一个栈,最好不要直接去使用它,而是用一个宏定义来代替它:

   #define sk_Student_sk_new(cmp) SKM_sk_new(Student, (cmp))

  以后要用sk_new的时候,直接用sk_Student_sk_new就可以了,不过上面这个宏里又出现了一个新东西:SKM_sk_new,其实,这也是一个宏,定义在safestack.h里:

   #define SKM_sk_new(type, cmp) sk_new((int (*)(const char * const *, const char * const *))(cmp))

  从这里,我们可以看出宏sk_Student_sk_new要求传入一个比较函数的函数指针,把这些宏展开我们可以看到,我们通过sk_Student_sk_new完成了对sk_new的调用。

  这只是一个例子,我们以后要使用上面介绍的函数时应该通过这种宏定义来调用:

   #define sk_Student_new_null() SKM_sk_new_null(Student)

   #define sk_Student_free(st) SKM_sk_free(Student, (st))

   #define sk_Student_num(st) SKM_sk_num(Student, (st))

            ...

            ...

            ...

  上面的操作函数要通过宏来使用,对栈的结构的使用也要宏来定义。如果程序里需要定义一个栈,且栈中保存的元素是指向Student的指针,则需要通过下面的方式来定义一个栈的类型。

   typedef STACK_OF(Student) Students;

  宏STACK_OF在文件safestack.h中被定义:

   #define STACK_OF(type) STACK

  这样看来,其实Students就是STACK了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值