C 海拾贝(一)

 

 

1.关于结构化编程.

写C代码也要有面向对象的思想,即以数据结构为中心,对一个对象的操作应尽量放在一个文件里,不要分散在很多文件里.
下面以设计一个会话(SESSION)为例来说明.
在session.h中先定义SESSION结构
struct SESSION {
 unsigned long SID; 
 SSH *ssh;   /* SESSION --> SSH */
 ...
};

在session.c中写出所有对SESSION进行操作的函数
SESSION *create() {...}
init(SESSION *cs) {...}
release(SESSION *cs) {...}

在SSH.h中定义
struct SSH {
 unsigned long time;
 SESSION *ss   /* SSH --> SESSION */
 ...
}; 

在ssh.c中实现对SSH的操作
SSH *create_ssh(const SESSION* ss) {...};
int release_ssh(SSH *ss) {...};

/*  SESSION和SSH这两种对象(结构)互相指向对方,是一种面向对象的常见设计手法,相当于对象的组合(而不是继承),
设计模式中的bridge讲的就是这个意思
*/

 

2.如何为系统设计权限
在设计一个系统时通常需要将登录者分为多种身份,不同的身份对同一资源具有不同的访问权限,如何设计?
这里共有三个概念:登录者,资源,对资源的访问(不同的资源对访问的定义不一样,如有的资源是读,有的资源是读/写/执行,有的资源是收/发等)
以下为相关数据结构:
struct USER {
 int UID;
 char name[8];
 char privilege;  /* 假设可取 0,2,3,...,7 */
 ...
}
在设计时,让登录者对象拥有一个属性:privilege(权限)

struct RES1 {
 char name[8];
 unsigned char read_pri;  /* 对resource的访问(读)位图,例如read_pri=9 (00001001) 可表示为privilege=0或3的 USER可读这个资源*/
 unsigned char write_pri; /* 对resource的访问(写)位图 */
 unsigned char exec_pri;  /* 对resource的访问(执行)位图 */   
 ...
}
这里把对RES1的访问分成了三种:读/写/执行,每种访问都用了一个char来表示其位图,三种访问权限位图总长24(3*8)
对资源RES1的读函数如下:
read_res1(const USER *a,RES1 *res1)
{
 if ( res1->read_pri & (1 << a->privilege ) ) {
  进行res1的读操作
 }
 else
 {
  权限不够
 }
}

在具体实现时也可以将read_pri,write_pri,exec_pri合并放在一个unsigned int里,操作时先进行移位,如
struct RES1 {
 char name[8];
 unsigned int pri; /* 对resource的访问位图(共32位,实际只需要24位,高8位无用),例如 pri=258 (00000000-000000001-00000010)(读-写-执行) 可表示为privilege=0的USER可写,privilege=1 USER可执行*/
 ...
}
对资源RES1的读函数如下:
read_res1(const USER *a,RES1 *res1)
{
 if ( (res1->pri>>16) & (1 << a->privilege ) ) {
  进行res1的读操作
 }
 else
 {
  权限不够
 }
}

总之如果privilege分为n种,访问类型有m种,那这个权限位图至少有(m*n)位.

3.用C语言模拟try-catch
设有传统C语言函数调用序列如下
A()
{
 ret=B();
 if (ret) {
  handle_err();
  return(ret);
 }
}

B()
{
 ret=C();
 if (ret) {
  handle_err();
  return(ret);
 }
}

C()
{
 ...
 if (OK)
  return 0;
 else {
  handle_err();
  return ret;
 }
}

如果这个函数调用嵌套层数很多A->B->C->D->...,每层都有出错处理,然后一层一层地退出来,
有时这种设计显得很繁,很需要一种类似于goto的语句,从一个函数直接跳出到最外层的函数,在C++中try-catch
可用来达到这个目的,在C语言中,应如何做呢?

以下使用C中的setjmp,longjmp模拟实现了C++中的try-catch,
#define TRY /
 exception=setjmp(mark);/
 if (!exception)

#define CATCH /
 if (exception)

#define THROW(a) /
 do {/
  longjmp(mark,a);/
 }/
 while(0)

#define HANDLE_EXCEPTION /
 do {/
  handle_error(exception));/
 } while(0)

int exception; /* 全局变量 */
jmp_buf mark;

void A()
{
 TRY
 {
  ...
  B();
  ...
  return;
 } 
 CATCH
 {
  HANDLE_EXCEPTION;
 } 
}

B()
{
 C(); 
}

C()
{
 ...
 if (error_code)
  THROW(error_code); /* 直接jmp至A函数*/
}

以上函数只是一个演示模型,不支持多线程。需要说明的是:不推荐使用setjmp,longjmp,因为现代CPU大都采用流水线结构,
而这两个函数会强制CPU清空指令缓存,因此在运行效率上会受到影响.

关于setjmp,longjmp的用法可参见其它参考资料.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值