天天看點

2021-2022-diocs-MyOD

20191218 2021-2022-diocs-MyOD

一、任務詳情

  1. 複習c檔案處理内容
  2. 編寫myod.c 用myod XXX實作Linux下od -tx -tc XXX的功能
  3. main與其他分開,制作靜态庫和動态庫
  4. 編寫Makefile
  5. 送出測試代碼和運作結果截圖, 送出調試過程截圖,要全屏,包含自己的學号資訊
  6. 在部落格園發表一篇部落格,重點寫遇到的問題和解決過程

二、實踐過程

1. C語言檔案操作歸納整理

C語言的檔案處理功能設定緩沖區的檔案處理方式:

當使用标準I/O函數(包含在頭檔案stdio.h中)時,系統會自動設定緩沖區,并通過資料流來讀寫檔案。當進行檔案讀取時,不會直接對磁盤進行讀取,而是先打開資料流,将磁盤上的檔案資訊拷貝到緩沖區内,然後程式再從緩沖區中讀取所需資料,

2021-2022-diocs-MyOD

當寫入檔案時,并不會馬上寫入磁盤中,而是先寫入緩沖區,隻有在緩沖區已滿或“關閉檔案”時,才會将資料寫入磁盤

2021-2022-diocs-MyOD

其餘有關内容可參考之前的部落格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的效果

2021-2022-diocs-MyOD
2021-2022-diocs-MyOD

代碼實作

我将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
           

複習制作靜态庫和動态庫

  • 靜态庫
    2021-2022-diocs-MyOD
    注意在第一次制作靜态庫時加上-Iinclude連結頭檔案,生成.a靜态庫之後可以不需要再加,直接編譯即可。
  • 動态庫
    2021-2022-diocs-MyOD
    注意每次都要加-Iinclude。

制作myod靜态庫和動态庫

  • tree下的結構圖
    2021-2022-diocs-MyOD
    用靜态庫運作myod結果
    2021-2022-diocs-MyOD
    可以看到實作了

    od -tx -tc XXX

    的要求
  • 2021-2022-diocs-MyOD
    上面這張截圖中我忘記添加-o參數指定輸出路徑,在目前目錄下生成了a.out,下圖是修改後的。
    2021-2022-diocs-MyOD
    下圖是在動态庫下的運作結果
    2021-2022-diocs-MyOD
  • 問題1:執行的時候不能找到動态庫,如下圖
    2021-2022-diocs-MyOD
    可以發現同靜态庫、直接用od指令結果一緻。

Makefile

makefile的存在主要是為了通過提前編寫好檔案依賴關系的腳本,實作自動化編譯運作,提高效率。

  • 制作makefile
    2021-2022-diocs-MyOD
  • Makefile練習
    2021-2022-diocs-MyOD
    myt實作的功能是:從鍵盤讀入兩整數,使用、輸出兩整數的和。
    2021-2022-diocs-MyOD
    嘗試使用對myod用makefile
    2021-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編譯。

解決辦法:

  1. 拷貝到系統的庫路徑下(不推薦)
  2. 修改LD_LIBRARY_PATH環境變量,将庫所在的路徑添加到環境變量中,用冒号分割。

    假設libfile.so在/root/LProject_20191218TangQiheng中

    export LD_LIBRARY_PATH=//root/LProject_20191218TangQiheng:$LD_LIBRARY_PATH

    2021-2022-diocs-MyOD
    教材上示範的也是這種方法。
  3. 修改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就可以正常運作。