20191218 2021-2022-diocs-MyOD
一、任務詳情
- 複習c檔案處理内容
- 編寫myod.c 用myod XXX實作Linux下od -tx -tc XXX的功能
- main與其他分開,制作靜态庫和動态庫
- 編寫Makefile
- 送出測試代碼和運作結果截圖, 送出調試過程截圖,要全屏,包含自己的學号資訊
- 在部落格園發表一篇部落格,重點寫遇到的問題和解決過程
二、實踐過程
1. C語言檔案操作歸納整理
C語言的檔案處理功能設定緩沖區的檔案處理方式:
當使用标準I/O函數(包含在頭檔案stdio.h中)時,系統會自動設定緩沖區,并通過資料流來讀寫檔案。當進行檔案讀取時,不會直接對磁盤進行讀取,而是先打開資料流,将磁盤上的檔案資訊拷貝到緩沖區内,然後程式再從緩沖區中讀取所需資料,

當寫入檔案時,并不會馬上寫入磁盤中,而是先寫入緩沖區,隻有在緩沖區已滿或“關閉檔案”時,才會将資料寫入磁盤
其餘有關内容可參考之前的部落格20191218 2021-2022-1-diocs第二周學習筆記
2. Linux下od指令
(1)功能
od指令用于将指定檔案内容以八進制、十進制、十六進制、浮點格式或ASCII編碼字元方式顯示,通常用于顯示或檢視檔案中不能直接顯示在終端的字元。
常見的檔案為文本檔案和二進制檔案。od指令主要用來檢視儲存在二進制檔案中的值,按照指定格式解釋檔案中的資料并輸出。
(2)指令格式
od [<選項><參數>] [<檔案名>]
(3)指令選項
-t<TYPE>
:指定輸出格式,格式包括a、c、d、f、o、u和x,各含義如下:
a:具名字元;
c:ASCII字元或者反斜杠;
d[SIZE]:十進制,正負數都包含,SIZE位元組組成一個十進制整數;
f[SIZE]:浮點,SIZE位元組組成一個浮點數;
o[SIZE]:八進制,SIZE位元組組成一個八進制數;
u[SIZE]:無符号十進制,隻包含正數,SIZE位元組組成一個無符号十進制整數;
x[SIZE]:十六進制,SIZE位元組為機關以十六進制輸出,即輸出時一列包含SIZE位元組。在預設條件下,以四個位元組為一組輸出
3. myod的實作
本次實踐中所涉及代碼已上傳到碼雲:第三周代碼
od -tx -tc XXX
是先在以十六進制輸出XXX檔案内容的同時,輸出位元組對應的ASCII值,它與 od -tx -tc XXX的差別在于輸出的次序
OpenEuler下od -tx -tc hello.c的效果
代碼實作
我将main函數放在myod.c檔案中,剩下需調用的函數放在了myod_func.c檔案中,所需的頭檔案放在myod.h中。
下面是各部分的代碼:
myod.c
#include "myod.h"
void main(int argc,char *argv[])
{
char str[BUFFERSIZE];
int num,i,j,i2;
int fd;
if((strcmp(argv[1], "-tx")!=0)|(strcmp(argv[2], "-tc")!=0))
{
printf("輸入格式錯誤");
exit(0);
}
for(num=0; num<strlen(str); num++)
str[num] = '0';
num = 0;
if ((fd = open(argv[3], O_RDONLY)) == -1 )
{
perror(argv[3]);
exit(1);
}
num = read(fd, str, BUFFERSIZE);
close(fd);
int LJ;
int SY;
int tx[8];
char tx2[8];
int tSY,Dan;
for(LJ = 0,SY = num;;)
{
for(j=0; j<8; j++)tx[j] = 0;
Change(LJ,tx,tx2);
for(j=0; j<8; j++)
printf("%c",tx2[j]);
printf(" ");
//累計字元輸出完畢
tSY = SY;
if(tSY>=16)
{
Dan = 16;
}
else
{
Dan = tSY;
}
for(j=LJ; j<Dan+LJ; j++)
{
if(str[j]=='\n')
{
printf("\\n ");
}
else
{
printf("%c \t",str[j]);
}
}
printf("\n");
//輸出文本
outputAscii(tx2,Dan,LJ,tx,str);
if(2==count(&tSY,&Dan,&LJ,&SY,&num))exit(0);
}
}
myod_func.c
#include "myod.h"
void Change(int LJ,int tx[],char tx2[])
{
dToH(LJ,tx);
int i;
for(i=0; i<8; i++)
{
tx2[i] = intToChar(tx[i]);
}
}
void dToH(int H,int tx[])//十進制轉十六進制,但此時仍用int存儲
{
if(H>536870911)
{
printf("字元數太大,超出限制\n");
exit (0);
}
int i=7;
for(; i>0;)
{
tx[i] = H%16;
H = H/16;
i--;
}
}
char intToChar(int t)//十六進制,把int[]轉為char[]
{
if((t>=0)&&(t<10))
{
return t+48;
}
else
{
return t+87;
}
}
int count(int *tSY,int *Dan,int *LJ,int *SY,int *num)//計數并判定是否終止
{
*tSY = *tSY-*Dan;
printf("\n");
if(*SY>=16)
{
*LJ = *LJ+16;
}
else if((*SY>0)&&(*SY<16))
{
*LJ = *LJ+*SY;
}
else if(*SY==0)
{
return 2;
}
*SY = *num-*LJ;
return 1;
}
void outputAscii(char tx2[],int Dan,int LJ,int tx[],char str[])
{
int tt,j,i2;
printf(" ");
for(j=LJ; j<Dan+LJ; j++)
{
tt = str[j];
Change(tt,tx,tx2);
for(i2=0; i2<8; i2++)
{
if(tx2[i2]!='0')break;
}
for(;i2<8;i2++)printf("%c",tx2[i2]);
printf(" \t");
}
printf("\n");
}
myod.h
#ifndef _MYOD_H_TQH_
#define _MYOD_H_TQH_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define BUFFERSIZE 1000
void Change(int LJ,int tx[],char tx2[]);
void dToH(int H,int tx[]);
char intToChar(int t);
int count(int *tSY,int *Dan,int *LJ,int *SY,int *num);
void outputAscii(char tx2[],int Dan,int LJ,int tx[],char str[]);
#endif
複習制作靜态庫和動态庫
- 靜态庫 注意在第一次制作靜态庫時加上-Iinclude連結頭檔案,生成.a靜态庫之後可以不需要再加,直接編譯即可。
2021-2022-diocs-MyOD - 動态庫 注意每次都要加-Iinclude。
2021-2022-diocs-MyOD
制作myod靜态庫和動态庫
- tree下的結構圖 用靜态庫運作myod結果
2021-2022-diocs-MyOD 可以看到實作了2021-2022-diocs-MyOD
的要求od -tx -tc XXX
- 上面這張截圖中我忘記添加-o參數指定輸出路徑,在目前目錄下生成了a.out,下圖是修改後的。
2021-2022-diocs-MyOD 下圖是在動态庫下的運作結果2021-2022-diocs-MyOD 2021-2022-diocs-MyOD - 問題1:執行的時候不能找到動态庫,如下圖 可以發現同靜态庫、直接用od指令結果一緻。
2021-2022-diocs-MyOD
Makefile
makefile的存在主要是為了通過提前編寫好檔案依賴關系的腳本,實作自動化編譯運作,提高效率。
- 制作makefile
2021-2022-diocs-MyOD - Makefile練習 myt實作的功能是:從鍵盤讀入兩整數,使用、輸出兩整數的和。
2021-2022-diocs-MyOD 嘗試使用對myod用makefile2021-2022-diocs-MyOD 首先是未在所有出現檔案前加上相對路徑,隻在gcc語句中出現的檔案加相對路徑,出現了如下提示2021-2022-diocs-MyOD 嘗試着都加上相對路徑2021-2022-diocs-MyOD 結果編譯報錯找不到頭檔案,一看還是忘了加-Iinclude選項2021-2022-diocs-MyOD 加上Iinclude選項後還是出錯2021-2022-diocs-MyOD 結果檢視樹形圖發現根本沒有myod_func.o,之前在編譯生成myod.o時已經是把兩個檔案一起編譯成myod.o目标檔案了,并且之前存放.o檔案的路徑也是在lib下2021-2022-diocs-MyOD 重新開始,又出現了新的問題2021-2022-diocs-MyOD 仔細檢查發現是gcc編譯的幾個參數弄混了,-c對應的才是生成目标檔案。2021-2022-diocs-MyOD 成功實作用Makefile完成gcc編譯。2021-2022-diocs-MyOD
解決辦法:
- 拷貝到系統的庫路徑下(不推薦)
-
修改LD_LIBRARY_PATH環境變量,将庫所在的路徑添加到環境變量中,用冒号分割。
假設libfile.so在/root/LProject_20191218TangQiheng中
export LD_LIBRARY_PATH=//root/LProject_20191218TangQiheng:$LD_LIBRARY_PATH
教材上示範的也是這種方法。2021-2022-diocs-MyOD - 修改sudo vi /etc/ld.so.conf,添加庫路徑在檔案中,sudo ldconfig -v (加-v的話是動态顯示加載過程,不加也行)
sudo vi /etc/ld.so.conf(在這裡面添加路徑)
sudo ldconfig -v (加-v的話是動态顯示加載過程,不加也行)
然後輸入
echo $LD_LIBRARY_PATH
,會顯示使用者在/etc/ld.so.conf中添加的路徑。
參考部落格Linux中靜态庫和動态庫的制作及釋出
- 問題2: 解決方案:加上
2021-2022-diocs-MyOD
參數即可-Iinclude
2021-2022-diocs-MyOD - 問題3:在運作生成的可執行檔案時出現段錯誤
2021-2022-diocs-MyOD 解決方案
在編譯過程忘記加對應參數了……加上-tx -tc xxx就可以正常運作。