中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么組織構建多文件C語言程序

發布時間:2021-11-03 17:00:51 來源:億速云 閱讀:152 作者:iii 欄目:編程語言

這篇文章主要講解了“怎么組織構建多文件C語言程序”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么組織構建多文件C語言程序”吧!

包含項目頭文件

位于第二部分中的 /* 01 項目包含文件 */ 的源代碼如下:

/* main.c - 喵嗚喵嗚流式編解碼器 */.../* 01 項目包含文件 */#include "main.h"#include "mmecode.h"#include "mmdecode.h"

#include 是 C 語言的預處理命令,它會將該文件名的文件內容拷貝到當前文件中。如果程序員在頭文件名稱周圍使用雙引號(""),編譯器將會在當前目錄尋找該文件。如果文件被尖括號包圍(<>),編譯器將在一組預定義的目錄中查找該文件。

main.h 文件中包含了 main.c 文件中用到的定義和類型定義。我喜歡盡可能多將聲明放在頭文件里,以便我在我的程序的其他位置使用這些定義。

頭文件 mmencode.h 和 mmdecode.h 幾乎相同,因此我以 mmencode.h 為例來分析。

/* mmencode.h - 喵嗚喵嗚流編解碼器 */  #ifndef _MMENCODE_H#define _MMENCODE_H  #include <stdio.h>  int mm_encode(FILE *src, FILE *dst);  #endif /* _MMENCODE_H */

#ifdef#define#endif 指令統稱為 “防護” 指令。其可以防止 C 編譯器在一個文件中多次包含同一文件。如果編譯器在一個文件中發現多個定義/原型/聲明,它將會產生警告。因此這些防護措施是必要的。

在這些防護內部,只有兩個東西:#include 指令和函數原型聲明。我在這里包含了 stdio.h 頭文件,以便于能在函數原型中使用 FILE 定義。函數原型也可以被包含在其他 C 文件中,以便于在文件的命名空間中創建它。你可以將每個文件視為一個獨立的命名空間,其中的變量和函數不能被另一個文件中的函數或者變量使用。

編寫頭文件很復雜,并且在大型項目中很難管理它。不要忘記使用防護。

喵嗚喵嗚編碼的最終實現

該程序的功能是按照字節進行 MeowMeow 字符串的編解碼,事實上這是該項目中最簡單的部分。截止目前我所做的工作便是支持允許在適當的位置調用此函數:解析命令行,確定要使用的操作,并打開將要操作的文件。下面的循環是編碼的過程:

/* mmencode.c - 喵嗚喵嗚流式編解碼器 */...   while (!feof(src)) {      if (!fgets(buf, sizeof(buf), src))       break;      for(i=0; i<strlen(buf); i++) {       lo = (buf[i] & 0x000f);       hi = (buf[i] & 0x00f0) >> 4;       fputs(tbl[hi], dst);       fputs(tbl[lo], dst);     }   }

簡單的說,當文件中還有數據塊時( feof(3) ),該循環讀取(feof(3) )文件中的一個數據塊。然后將讀入的內容的每個字節分成兩個 hilo半字節nibble。半字節是半個字節,即 4 個位。這里的奧妙之處在于可以用 4 個位來編碼 16 個值。我將 hilo 用作 16 個字符串查找表 tbl 的索引,表中包含了用半字節編碼的 MeowMeow 字符串。這些字符串使用 fputs(3) 函數寫入目標 FILE 流,然后我們繼續處理緩存區的下一個字節。

該表使用 table.h 中的宏定義進行初始化,在沒有特殊原因(比如:要展示包含了另一個項目的本地頭文件)時,我喜歡使用宏來進行初始化。我將在未來的文章中進一步探討原因。

喵嗚喵嗚解碼的實現

我承認在開始工作前花了一些時間。解碼的循環與編碼類似:讀取 MeowMeow 字符串到緩沖區,將編碼從字符串轉換為字節

 /* mmdecode.c - 喵嗚喵嗚流式編解碼器 */ ... int mm_decode(FILE *src, FILE *dst) {   if (!src || !dst) {     errno = EINVAL;     return -1;   }   return stupid_decode(src, dst); }

這不符合你的期望嗎?

在這里,我通過外部公開的 mm_decode() 函數公開了 stupid_decode() 函數細節。我上面所說的“外部”是指在這個文件之外。因為 stupid_decode() 函數不在該頭文件中,因此無法在其他文件中調用它。

當我們想發布一個可靠的公共接口時,有時候會這樣做,但是我們還沒有完全使用函數解決問題。在本例中,我編寫了一個 I/O  密集型函數,該函數每次從源中讀取 8 個字節,然后解碼獲得 1 個字節寫入目標流中。較好的實現是一次處理多于 8  個字節的緩沖區。更好的實現還可以通過緩沖區輸出字節,進而減少目標流中單字節的寫入次數。

/* mmdecode.c - 喵嗚喵嗚流式編解碼器 */...int stupid_decode(FILE *src, FILE *dst){  char           buf[9];  decoded_byte_t byte;  int            i;      while (!feof(src)) {    if (!fgets(buf, sizeof(buf), src))      break;    byte.field.f0 = isupper(buf[0]);    byte.field.f1 = isupper(buf[1]);    byte.field.f2 = isupper(buf[2]);    byte.field.f3 = isupper(buf[3]);    byte.field.f4 = isupper(buf[4]);    byte.field.f5 = isupper(buf[5]);    byte.field.f6 = isupper(buf[6]);    byte.field.f7 = isupper(buf[7]);          fputc(byte.value, dst);  }  return 0;}

我并沒有使用編碼器中使用的位移方法,而是創建了一個名為 decoded_byte_t 的自定義數據結構。

/* mmdecode.c - 喵嗚喵嗚流式編解碼器 */... typedef struct {  unsigned char f7:1;  unsigned char f6:1;  unsigned char f5:1;  unsigned char f4:1;  unsigned char f3:1;  unsigned char f2:1;  unsigned char f1:1;  unsigned char f0:1;} fields_t;  typedef union {  fields_t      field;  unsigned char value;} decoded_byte_t;

初次看到代碼時可能會感到有點兒復雜,但不要放棄。decoded_byte_t 被定義為 fields_tunsigned char聯合。可以將聯合中的命名成員看作同一內存區域的別名。在這種情況下,valuefield 指向相同的 8 位內存區域。將 field.f0 設置為 1 也將會設置 value 中的最低有效位。

雖然 unsigned char 并不神秘,但是對 fields_t 的類型定義(typedef)也許看起來有些陌生。現代 C 編譯器允許程序員在結構體中指定單個位字段的值。字段所在的類型是一個無符號整數類型,并在成員標識符后緊跟一個冒號和一個整數,該整數指定了位字段的長度。

這種數據結構使得按字段名稱訪問字節中的每個位變得簡單,并可以通過聯合中的 value 字段訪問組合后的值。我們依賴編譯器生成正確的移位指令來訪問字段,這可以在調試時為你節省不少時間。

最后,因為 stupid_decode() 函數一次僅從源 FILE 流中讀取 8 個字節,所以它效率并不高。通常我們嘗試最小化讀寫次數,以提高性能和降低調用系統調用的開銷。請記住:少量的讀取/寫入大的塊比大量的讀取/寫入小的塊好得多。

感謝各位的閱讀,以上就是“怎么組織構建多文件C語言程序”的內容了,經過本文的學習后,相信大家對怎么組織構建多文件C語言程序這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

屯门区| 武乡县| 新邵县| 宝坻区| 大荔县| 霍邱县| 汕头市| 鹤壁市| 大悟县| 曲沃县| 专栏| 桂平市| 彭泽县| 丰镇市| 昌黎县| 叶城县| 济宁市| 渝北区| 通榆县| 鲜城| 新乡市| 霍城县| 新巴尔虎左旗| 凤凰县| 古丈县| 砚山县| 南华县| 盐亭县| 那曲县| 长寿区| 始兴县| 吴江市| 上虞市| 班戈县| 苍梧县| 长宁区| 昔阳县| 四会市| 临颍县| 渝中区| 岱山县|