C語言介面與實現方法執行個體詳解_C 語言

來源:互聯網
上載者:User

本文以執行個體形式詳細講述了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 <stddef.h>#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)實現了可檢查的運行期錯誤,它禁止null 指標傳給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 <stddef.h>#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程式設計有一定的借鑒價值。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.