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函式
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 存在的檔案 新的檔名
要求:
檔案存在就拷貝,不存在提示錯誤.