您好,欢迎来到尚车旅游网。
搜索
您的当前位置:首页C语言接口与实现方法实例详解

C语言接口与实现方法实例详解

来源:尚车旅游网
C语⾔接⼝与实现⽅法实例详解

本⽂以实例形式详细讲述了C语⾔接⼝与实现⽅法,对于深⼊掌握C语⾔程序设计有⼀定的借鉴价值。分享给⼤家供⼤家参考。具体分析如下:

⼀般来说,⼀个模块有两部分组成:接⼝和实现。接⼝指明模块要做什么,它声明了使⽤该模块的代码可⽤的标识符、类型和例程,实现指明模块是如何完成其接⼝声明的⽬标的,⼀个给定的模块通常只有⼀个接⼝,但是可能会有许多种实现能够提供接⼝所指定的功能。每个实现可能使⽤不同的算法和数据结构,但是它们都必须符合接⼝所给出的使⽤说明。客户调⽤程序是使⽤某个模块的⼀段代码,客户调⽤程序导⼊接⼝,⽽实现导出接⼝。由于多个客户调⽤程序是共享接⼝和实现的,因此使⽤实现的⽬标代码避免了不必要的代码重复,同时也有助于避免错误,因为接⼝和实现只需⼀次编写和调试就可多次使⽤。接⼝

接⼝只需要指明客户调⽤程序可能使⽤的标识符即可,应尽可能地隐藏⼀些⽆关的表⽰细节和算法,这样客户调⽤程序可以不必依赖于特定的实现细节。这种客户调⽤程序和实现之间的依赖--耦合----可能会在实现改变时引起错误,当这种依赖性埋藏在⼀些关于实现隐藏的或是不明确的假设中时,这些错误可能很难修复,因此⼀个设计良好且描述精确的接⼝应该尽量减少耦合。

C语⾔对接⼝和实现的分离只提供最基本的⽀持,但是简单的约定能给接⼝/实现⽅带来巨⼤的好处。在C中,接⼝在头⽂件声明,头⽂件声明了客户调⽤程序可以使⽤的宏、类型、数据结构、变量以及例程。⽤户使⽤C语⾔的预处理指令#include导⼊接⼝。

下⾯的例⼦说明了本篇⽂章的接⼝中所使⽤的⼀些约定、接⼝:

extern int Arith_max(int x, int y);extern int Arith_min(int x, int y);extern int Arith_div(int x, int y);extern int Arith_mod(int x, int y);extern int Arith_ceiling(int x, int y);extern int Arith_floor (int x, int y);

该接⼝的名字为Arith,接⼝头⽂件也相应地命名为arith.h,接⼝的名字以前缀的形式出现在接⼝的每个标识符中。模块名不仅提供了合适的前缀,⽽且还有助于整理客户调⽤程序代码。

Arith接⼝还提供了⼀些标准C函数库中没有但是很有⽤的函数,并为出发和取模提供了良好的定义,⽽标准C中并没有给出这些操作的定义和只提供基于实现的定义。实现

⼀个实现导出⼀个接⼝,它定义了必要的变量和函数以提供接⼝所规定的功能,在C语⾔中,⼀个实现是由⼀个或多个.c⽂件提供的,⼀个实现必须提供其导出的接⼝所指定的功能。实现应包含接⼝的.h⽂件,以保证它的定义和接⼝的声明时⼀致的。Arith_min和Arith_max返回其整型参数中的最⼩值和最⼤值:

int Arith_max(int x, int y) { return x > y ? x : y;}

int Arith_min(int x, int y) { return x > y ? y : x;}

Arith_div返回y除以x得到的商,Arith_mod返回相应的余数。当x与y同号的时候,Arith_div(x,y)等价于x/y,Arith_mod(x,y)等价于x%y

当x与y的符号不同的时候,C的内嵌操作的返回值就取决于具体的实现:如果-13/5=2,-13%5=-3,如果-13/5=-3,-13%5=2

标准库函数总是向零取整,因此div(-13,2)=-2,Arith_div和Arith_mod的语义同样定义好了:它们总是趋近数轴的左侧取整,因此Arith_div(-13,5)=-3,Arith_div(x,y)是不超过实数z的最⼤整数,其中z满⾜z*y=x。Arith_mod(x,y)被定义为x-y*Arith_div(x,y)。因此Arith_mod(-13,5)=-13-5*(-3)=2

函数Arith_ceiling和Arith_floor遵循类似的约定,Arith_ceiling(x,y)返回不⼩于实数商x/y的最⼩整数Arith_floor(x,y)返回不超过实数商x/y的最⼤整数

完整实现代码如下:

#include \"arith.h\"

int Arith_max(int x, int y) { return x > y ? x : y;}

int Arith_min(int x, int y) { return x > y ? y : x;}

int Arith_div(int x, int y) { if (-13/5 == -2

&& (x < 0) != (y < 0) && x%y != 0) return x/y - 1; else

return x/y;}

int Arith_mod(int x, int y) { if (-13/5 == -2

&& (x < 0) != (y < 0) && x%y != 0) return x%y + y; else

return x%y;}

int Arith_floor(int x, int y) { return Arith_div(x, y);}

int Arith_ceiling(int x, int y) {

return Arith_div(x, y) + (x%y != 0);}

抽象数据类型

抽象数据类型(abstract data type,ADT)是⼀个定义了数据类型以及基于该类型值提供的各种操作的接⼝

⼀个⾼级类型是抽象的,因为接⼝隐藏了它的表⽰细节,以免客户调⽤程序依赖这些细节。下⾯是⼀个抽象数据类型(ADT)的规范化例⼦--堆栈,它定义了该类型以及五种操作:

#ifndef STACK_INCLUDED#define STACK_INCLUDED#define T Stack_Ttypedef struct T *T;

extern T Stack_new (void);extern int Stack_empty(T stk);

extern void Stack_push (T stk, void *x);extern void *Stack_pop (T stk);extern void Stack_free (T *stk);#undef T#endif

实现

包含相关头⽂件:

#include #include \"assert.h\"#include \"mem.h\"#include \"stack.h\"#define T Stack_T

Stack_T的内部是⼀个结构,该结构有个字段指向⼀个栈内指针的链表以及⼀个这些指针的计数:

struct T { int count; struct elem { void *x;

struct elem *link; } *head;};

Stack_new分配并初始化⼀个新的T:

T Stack_new(void) { T stk;

NEW(stk);

stk->count = 0;

stk->head = NULL; return stk;}

其中NEW是⼀个另⼀个接⼝中的⼀个分配宏指令。NEW(p)将分配该结构的⼀个实例,并将其指针赋给p,因此Stack_new中使⽤它就可以分配⼀个新的Stack_T

当count=0时,Stack_empty返回1,否则返回0:

int Stack_empty(T stk) { assert(stk);

return stk->count == 0;}

assert(stk)实现了可检查的运⾏期错误,它禁⽌空指针传给Stack中的任何函数。Stack_push和Stack_pop从stk->head所指向的链表的头部添加或移出元素:

void Stack_push(T stk, void *x) { struct elem *t; assert(stk); NEW(t); t->x = x;

t->link = stk->head; stk->head = t; stk->count++;}

void *Stack_pop(T stk) { void *x;

struct elem *t; assert(stk);

assert(stk->count > 0); t = stk->head;

stk->head = t->link; stk->count--; x = t->x; FREE(t); return x;}

FREE是另⼀个接⼝中定义的释放宏指令,它释放指针参数所指向的空间,然后将参数设为空指针

void Stack_free(T *stk) { struct elem *t, *u; assert(stk && *stk);

for (t = (*stk)->head; t; t = u) { u = t->link; FREE(t); }

FREE(*stk);}

完整实现代码如下:

#include #include \"assert.h\"#include \"mem.h\"#include \"stack.h\"#define T Stack_Tstruct T { int count; struct elem { void *x;

struct elem *link; } *head;};

T Stack_new(void) { T stk;

NEW(stk);

stk->count = 0; stk->head = NULL; return stk;}

int Stack_empty(T stk) { assert(stk);

return stk->count == 0;}

void Stack_push(T stk, void *x) { struct elem *t; assert(stk); NEW(t); t->x = x;

t->link = stk->head; stk->head = t; stk->count++;}

void *Stack_pop(T stk) { void *x;

struct elem *t; assert(stk);

assert(stk->count > 0); t = stk->head;

stk->head = t->link; stk->count--; x = t->x; FREE(t); return x;}

void Stack_free(T *stk) { struct elem *t, *u; assert(stk && *stk);

for (t = (*stk)->head; t; t = u) { u = t->link; FREE(t); }

FREE(*stk);}

相信本⽂所述对⼤家的C程序设计有⼀定的借鉴价值。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- sceh.cn 版权所有 湘ICP备2023017654号-4

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务