客戶呼叫程式是使用某個模組的一段程式碼,客戶呼叫程式匯入介面,而實現匯出介面。由於多個客戶呼叫程式是共享介面和實現的,因此使用實現的目標程式碼避免了不必要的程式碼重複,同時也有助於避免錯誤,因為介面和實現只需一次編寫和除錯就可多次使用。以下是小編為大家搜尋整理的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.h
該介面的名字為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的內嵌操作的返回值就取決於具體的實現:
eg.如果-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);
}
arith.c
抽象資料型別
抽象資料型別(abstract data type,ADT)是一個定義了資料型別以及基於該型別值提供的各種操作的介面
一個高階型別是抽象的,因為介面隱藏了它的表示細節,以免客戶呼叫程式依賴這些細節。下面是一個抽象資料型別(ADT)的規範化例子--堆疊,它定義了該型別以及五種操作:
#ifndef STACK_INCLUDED
#define STACK_INCLUDED
#define T Stack_T
typedef 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
stack.h
實現
包含相關標頭檔案:
#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_T
struct 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);
}
stack.c