close
可能因為老江也是做OS又超愛linux的關係 所以作業都跟linux系統有關

作業主要是要我們實作出unix系統中xxd指令的功能

xxd的用法如下:

$ xxd   Makefile  

紅色表示我們要轉換的文件名稱 ,之後將文件內容轉成16進位格式 

輸出畫面:
 
0000000: 2320 4120 7361 6d70 6c65 206d 616b 6520 # A sample make
0000010: 6669 6c65 2066 6f72 2074 6865 2068  6f6d  file for the hom
0000020: 6577 6f72 6b20 6173 7369 676e 6d65  6e74 ework assignment
0000030: 0a0a 5352 4353 203a 3d20 2428 7368 656c ..SRCS := $(shel
0000040: 6c20 6c73  202a 2e63 7070 290a 4f42 4a53 l ls *.cpp).OBJS
0000050: 203a 3d20 2428 5352 4353 3a2e 6370 703d := $(SRCS:.cpp=
0000060: 2e6f  290a 4558 4543 203a 3d20 6d79 7878 .o).EXEC := myxx
0000070: 640a 0a61 6c6c 3a20 2428 4558 4543 290a d..all: $(EXEC).
0000080: 0a6d 7978 7864 3a20 2428 4f42 4a53 290a .myxxd: $(OBJS).

*以第一行為例 : #的16進位就是23   空白的16進位為20

  一行可分為三個部份
  
   1.行數: 0000000,0000010.....
   2.16進位格式
   3.文件內容 無法印出部份(如空白)用'.'表示
-----------------------------------------------------------------------------------------------------

這個作業主要是要我們瞭解

1.利用C++中stream的觀念來對檔案做存取操作的動作

2.利用C++的一些I/O函式對程式結果做排版

3.程式切割的用途及makefile的撰寫

-----------------------------------------------------------------------------------------------------

我在這次作業的作法程序就是

開啟目標檔案->逐字讀取->滿一行(16個字),印出結果->換行
                         ︿
                           |____________________________|


1.stream的開啟及操作
   
   C++對於輸出輸入的資料都以資料流的方式來控制

   例如最常看到的"cout"
 
   cout<<"moli";    

  上面就是把"moli"這字串流向cout這個函式中做處理
 
  再來就是這次作業要做的事:把一個檔案以資料流的方式開啟

  ifstream inStream;     //宣告一個input stream型態的變數   變數名稱為inStream
         
  inStream.open(Source);   //將名稱為Source的檔案打開  並將inSream指向此檔案

  開啟成功後 便使用get()這個Stream的member function一字一字的讀進來

  while(inStream.get(ch)) {       //將InStream所讀的字元放進ch
      ubuffer[count]=ch;               //將ch存放到ubuffer (將來要印出文件內容要用的)
     myprint(ch,count,LineCnt); //將目前所讀到的字元及行數傳入myprint函式做輸出
      count++;                                //count為紀錄字元數
      if(count<LineLen) continue;  //未滿16個(一行的字元數)就繼續做讀取字元的動作
      else {
         cout<<" ";                               //滿一行 印出之前所讀的文件內容
         HumanRead(ubuffer,count);
         count=0;
         LineCnt++;
         cout<<endl;
      }   
   }

2.輸出結果排版

 輸出結果我分成兩部分的函式來進行

 (1)行數+16進位格式 myprintf(...)

   
 (2)文件內容  HumanRead(...)

 
void myprint(char ch,int count,int LineCnt)        //print hex format
{
   if(count==0) cout<<setw(6)<<setfill('0')<<(hex)<<LineCnt<<setw(2)<<setfill('0')<<":"<<" ";  
     //假如尚未讀入字元  印出行數
 
         cout<<hex<<right<<setw(2)<<setfill('0')<<(int)ch;
         //印出16進位的前一個部份
   if((count%2)!=0) cout<<" ";
  //印出16進位的後一個部份
    
}

void HumanRead(unsigned char* ubuffer,int count)  //human readable part
{
  for(int q=0;q<count;q++) {    //將之前ubuffer存入的字元印出
     if(isprint(ubuffer[q])) cout<<ubuffer[q];  
     else cout<<"."; //若無法印出 以"".代替
  }
}

3.程式切割&Makefile

 作業要求整個程式需分為main.cpp  , myxxd.cpp , myxxd.h

 main.cpp也就是我們的主程式

 他其實就是一個driver.要去"驅動"我們要的功能

 只做驅動的動作(也就是呼叫我們的功能函式)  其他事就不做了

所以一般來說 main都是短短幾行 且不對資料做任何運算處理的動作

myxxd.h myxxd.cpp

所謂標頭檔(header file)其實就是提供給使用者知道的介面(interface)

裡面大多只有功能函式的宣告

使用者只要知道當include這個標頭檔後有哪些功能可以用及丟什麼參數就好

ex:  myxxd.h
 
#include<iostream>   //以下為要用到的其他函式庫
#include<fstream>
#include<iomanip>
#include<ctype.h>
 
using namespace std; 
 
void myxxd(char* Target);       // 程式設計者自訂的函式宣告
void myprint(char ch,int count,int LineCnt);
void HumanRead(char* ubuffer);

而上述那些功能函式的實現(Implement)

也就是怎麼去完成那些功能的實際作法等

就寫在myxxd.cpp裡
    
最後Makefile比較要記的就是make dep

dep:
$(CXX) -M $(SRCS) >depend

上面的動作主要是把在整個程式編譯時所建立的相依性(dependency)

寫入.depend裡  我們可以由這檔案看到各程式碼檔案之間的關係













 





arrow
arrow
    全站熱搜

    molimomo 發表在 痞客邦 留言(0) 人氣()