1. 程式人生 > >linux高階程式設計day03 筆記(轉)

linux高階程式設計day03 筆記(轉)

一、make與makefile
  1.回顧:
    目標的語法
    目標名:依賴目標
      @命令
      @命令
      
    make的命令列使用
      make -f make指令碼檔案  目標名
  2.目標的劃分
    目標依賴

  3.預設規則:
    a.不指定目標,執行第一個目標
    b.不指定make檔案,預設檔案是makefile Makefile
      makefile優先
  4.目標的呼叫規則:(make把目標當成當前資料夾下同名的檔案)
    make執行目標:
      搜尋與目標相同的檔案
      如果檔案存在,則判定檔案是否被修改過。
      檔案未被修改,則停止執行,輸出提示
      檔案修改過,則進行執行。(檔案不存在屬於被修改過範疇)

      比較:當前目標與依賴目標
  5.建議:
    只要有檔案輸出,就把任務作為一個目標,並且把輸出的檔案作為目標名。
    範例:
    input.o:input.c
       gcc -c -fpic input.c
    libdemo.so:input.o
       gcc -shared -olibdemo.so input.o
    demo:libdemo.so demo.c
       gcc demo.c -ldemo -L. -odemo
  
  6.潛規則(不建議)
    適用於:.c目標與.o目標。
    查詢.o目標,目標不存在,就把.o替換成.c
    如果.c存在,實施潛規則:直接呼叫gcc把.c執為.o
  7.變數
    變數名=值 值
    
    $(變數名)  ${變數}  
  8.偽目標:
    不把目標作為檔案處理的目標稱為偽目標
    宣告偽目標
    .PHONY=目標  

二、環境變數
  1.使用main的引數
  int main(int args,char *argv[],char **arge)
  {
  }
  命令列引數argv與環境行arge都是字串陣列.
  約定:最後一個字串是NULL/0
  2.在C的標準庫提供:外部變數
   extern char **environ;


#include <stdio.h>
#include <unistd.h>
extern char **environ;
int main(/*int args,char *argv[],char*arge[]*/)
{
    /*
    while(*arge)
    {
        printf("%s\n",*arge);
        arge++;
    }
    
*/
    /*
    int i=0;
    while(arge[i])
    {
        printf("%s\n",arge[i]);
        i++;
    }
    
*/
    while(*environ)
    {
        printf("%s\n",*environ);
        environ++;
    }
}
3.修改獲取某個環境變數
    getenv/setenv/unsetenv

#include <stdlib.h>
#include <stdio.h>
main()
{
    char *val;
    val=getenv("PATH");
    printf("%s\n",val);
}三、IO的基礎
  1.認識核心物件
    不允許訪問核心裝置和記憶體,但可以通過核心系統函式去訪問.
    對每個核心物件進行編號ID.
    如果訪問核心物件,只能通過ID.
    程式設計模型:
      申請得到一個ID
      在核心系統函式中使用ID得到對應核心物件資料
  2.怎麼訪問檔案
    使用函式,傳遞一個檔案,系統開啟檔案,載入檔案資料,
    返回一個ID.
    使用函式,傳遞ID,得到資料.
    使用函式傳遞ID,告訴系統釋放檔案.

    ID:檔案描述符號.file description (fd)

    每個程式執行的時候都有一個目錄,存放開啟的檔案描述符號
  3.每個程式預設開啟三個檔案裝置:
    0:標準輸入
    1:標準輸出
    2:錯誤輸出
  4.操作檔案描述符號
    ssize_t write(int fd,
     void *buf,//要寫入核心物件的資料
     size_t size);//寫入資料大小
    返回:
      >0 實際寫入的資料
      -1 寫入錯誤 
    ssize_t read(int fd,
      void *buf,//返回資料的空間
      size_t size);//空間大小
    返回:
      >0:實際讀取的資料
      =0:碰到檔案結束符號EOF (ctrl+d)
      -1:讀取錯誤

    建議:
      0:輸入
      1:輸出
      2:錯誤輸出
課堂練習:
  1.使用write向0 1 2 寫資料
  2.使用read從0 1 讀取資料,並判定輸入的情況,然後根據相應的結果輸出提示

#include <stdlib.h>
#include <stdio.h>
main()
{
    //printf("%d\n",getpid());
    
//while(1);    /*
    int r=write(0,"Hello\n",6);
    write(1,"world\n",6);
    write(2,"louis\n",6);
    int a=20;
    
    write(1,&a,4);
    
*/
    char buf[32];
    //memset(buf,0,32);    bzero(buf,32);
    
    int r=read(0,buf,30);
    printf("實際輸入:%d\n",r);
    if(r>0)
    {
        buf[r]=0;
        printf("::%s\n",buf);
    }
    if(r==0)
    {
        printf("ctrl+d\n");
    }
    if(r==-1)
    {
        printf("輸入錯誤!\n");
    }
}

三.基於檔案的描述符號
  1.得到檔案描述符號/釋放檔案描述符號
   a.檔案型別
    目錄檔案d
    普通檔案f
    字元裝置檔案c
    塊裝置檔案b
    軟連線檔案l
    管道檔案p
    socket檔案s   
   b.檔案的屬性
     1.屬性的表達方式:絕對模式(0666類似的八進位制數),字元模式(rwx)
       0    0   0    0
          擁有者   組   其他使用者
       0666
     2.檔案的許可權屬性:
       讀
       寫
       執行
       粘附位許可權
       使用者設定位許可權
       組設定位許可權
      0   0         0      0       0
        特殊許可權   Owner  group  其他使用者

       s:
       S
       t
       T
      2.1.  s設定位
          2:組設定位
          4:使用者設定位
         s對執行有效
         無效的設定位使用S表示
         
         設定位向其他使用者開放擁有者許可權的許可權.使用者設定位
         設定位向其他使用者開放組使用者許可權的許可權.組使用者設定位
         設定位只對執行程式有意義(執行許可權有意義)
         
      2.2.  t設定位
          1:表示沾附位設定
          t對寫檔案有意義
         沒有執行許可權的沾附位使用T表示.
         沾附的目的:防止有些許可權的使用者刪除檔案.
      
      程式在執行的時候到底擁有的是執行者使用者的許可權
      還是檔案擁有者的許可權.(看setUID)
       程式執行中有兩個使用者:
          實際使用者:標示程序到底是誰
          有效使用者:標示程序訪問資源的許可權
       上述一般情況是一樣的,有時候被setUID改變      
   總結:
     沾附位的作用: 防止其他有寫許可權使用者刪除檔案
     設定位的作用: 向其他執行者開發組或者使用者的許可權.
練習:
  1.使用cat建立一個檔案
  2.設定沾附位,並觀察屬性
  3.設定使用者設定位, 並觀察屬性
  4.設定組設定位, 並觀察屬性
  5.考慮w許可權與沾附位的關係
  6.考慮x許可權與設定位的關係.

  2.通過檔案描述符號讀寫各種資料.      
    open函式與creat函式

 int open(
                    const char *filename,//檔名                    int flags,//open的方式[建立/開啟]                    mode_t mode//許可權(只有建立的時候有效)                    )

 返回:
      >=0:核心檔案描述符號.
      =-1:開啟/建立失敗
  
    open的方式:
      必選方式:O_RDONLY O_WRONLY O_RDWR,必須選擇一個
      建立/開啟:O_CREAT
      可選方式:
          對開啟可選方式:O_APPEND  O_TRUNC(清空資料)
          對建立可選方式:O_EXCL
     組合:
        建立:
          O_RDWR|O_CREAT
          O_RDWR|O_CREAT | O_EXCL 
        
        開啟:          
          O_RDWR
          O_RDWR|O_APPEND
          O_RDWR|O_TRUNC
     許可權:
       建議使用8進位制數
    關閉 
    void  close(int fd);           

案例1:
  建立檔案
案例2:
  建立檔案並寫入資料
    20  short float
    tom  20   99.99
    bush  70   65.00
    達內  40   100.00
  注意:
    檔案的建立的許可權受系統的許可權遮蔽的影響
    umask    //顯示遮蔽許可權.
    umask 0666  //設定許可權遮蔽.   
    
    ulimit -a 顯示所有的其他限制.


/*建立檔案*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main()
{
    int fd;
    
    char name[20];
    short age;
    float score;
    char sex;
    
    fd=open("test.dat",
        O_RDWR|O_CREAT|O_EXCL,
);
    if(fd==-1) printf("open error:%m\n"),exit(-1);
    
    
    //寫第一條    memcpy(name,"tom",strlen("tom")+1);
    age=20;
    score=99.99;
    sex='F';
    
    write(fd,name,sizeof(name));
    write(fd,&age,sizeof age);
    write(fd,&score,sizeof(float));
    write(fd,&sex,sizeof(sex));
    
    //寫第二條    memcpy(name,"Bush",strlen("Bush")+1);
    age=70;
    score=65.00;
    sex='M';
    write(fd,name,sizeof(name));
    write(fd,&age,sizeof age);
    write(fd,&score,sizeof(float));
    write(fd,&sex,sizeof(sex));
    
    //寫第三條    
    memcpy(name,"達內",strlen("達內")+1);
    age=10;
    score=99.00;
    sex='F';
    write(fd,name,sizeof(name));
    write(fd,&age,sizeof age);
    write(fd,&score,sizeof(float));
    write(fd,&sex,sizeof(sex));
        
    close(fd);
}案例3:
  開啟檔案讀取資料
  重點:
    怎麼開啟讀取
    檔案尾的判定

  基本型別的資料讀寫.
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

main()
{
    char name[20];
    short age;
    float score;
    char sex;
    int fd;
    int r;
    fd=open("test.dat",O_RDONLY);
    if(fd==-1) printf("open error:%m\n"),exit(-1);
    
    while(1)
    {
        r=read(fd,name,sizeof(name));
        if(r==0) break;
        r=read(fd,&age,sizeof(short));
        r=read(fd,&score,sizeof(float));
        r=read(fd,&sex,sizeof(sex));
        printf("%s,\t%4hd,\t%.2f,\t%1c\n",
                name,age,score,sex);
    }
    
    close(fd);
}案例4:
  結構體讀取
  描述:從鍵盤讀取若干條資料,儲存到檔案
     資料追加
View Code 

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
struct stu
{
    int no;
    char name[20];
    float score;
};
/*
.判定檔案是否存在,存在開啟,不存在建立
.輸入記錄
.儲存記錄
.提示繼續輸入
.繼續/不繼續
.關閉檔案
*/
int openfile(const char *filename)
{
    int fd;
    fd=open(filename,O_RDWR|O_CREAT|O_EXCL,0666);
    if(fd==-1)//表示檔案存在,則開啟    {
        fd=open(filename,O_RDWR|O_APPEND);
        return fd;
    }
    return fd;
}
void input(struct stu *record)
{
    bzero(record,sizeof(struct stu));
    printf("輸入學號:");
    scanf("%d",&(record->no));
    printf("輸入姓名:");
    scanf("%s",record->name);
    printf("輸入成績:");
    scanf("%f",&(record->score));
}
void save(int fd,struct stu *record)
{
    write(fd,record,sizeof(struct stu));
}
int iscontinue()
{
    char c;
    printf("是否繼續輸入:\n");
    //fflush(stdin);
    
//fflush(stdout);    scanf("\n%c",&c);    
    if(c=='Y' || c=='y')
    {
        return 1;
    }
    return 0;
}

int main()
{
    int fd;
    int r;
    struct stu s={0};
    fd=openfile("stu.dat");
    if(fd==-1) printf("openfile:%m\n"),exit(-1);
    
    while(1)
    {
        input(&s);
        save(fd,&s);
        r=iscontinue();
        if(r==0) break;
        system("clear");
    }
    close(fd);
    printf("輸入完畢!\n");    
}3.檔案描述符號與重定向
     1.判定檔案描述符號與終端的邦定關係
     int isatty(int fd)
     返回非0:fd輸出終端
        0:fd輸出被重定向
     2.防止重定向
       /dev/tty
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int fd;
    printf("Hello\n");
    write(1,"World\n",6);
    fd=open("/dev/tty",O_WRONLY);
    if(isatty(1))
    {
        write(1,"notredir\n",9);
    }
    else
    {
        write(1,"redir\n",6);
    }
    write(fd,"Killer\n",7);
}

總結:
  1.make的多目標依賴規則以及偽目標
  2.檔案的建立與開啟(瞭解設定位的作用)
  3.檔案的讀寫(字串/基本型別/結構體)
  4.瞭解描述符號與重定向

作業:
  1.完成上課的練習.
  2.寫一個程式使用結構體讀取1種的資料,
     並全部列印資料,
     並列印平均成績
  3.寫一個程式:
    查詢1種的資料.比如:輸入姓名,查詢成績
  4.寫一個程式,錄入儲存如下資料:
    書名  出版社  價格  儲存量  作者  
  5.寫一個程式負責檔案拷貝
    main 存在的檔案  新的檔名
    要求:
      檔案存在就拷貝,不存在提示錯誤.