#include<stdio.h>
#include<string.h>
int main()
{
FILE * handle;
char con[100];
//第一種使用fopen的方式,windows系統是直接輸入文件的絕對路徑需要這種方式"e:\\aaa.txt",注意是兩個反斜杠,一個反斜杠的話就錯了
//handle=fopen("e:\aaa.txt","r");
//第二種使用fopen的方式,利用一個字符串來保存文件路徑和名字,運行程序后,在dos下提示你輸入路徑名字,可以輸入"e:\\aaa.txt",
//或者"e:\aaa.txt",也就是說dos下一個反斜杠或者兩個反斜杠都是正確的
//char buf[80];
//printf("please input the filename you want to open:");
//gets(buf);
//handle=fopen(buf,"r");
//利用一個初始化好的字符串也可以正確的使用fopen,以下這幾種初始化方式都是正確的都是兩個反斜杠
//char buf[]="e:\\aaa.txt";const char buf[100]="e:\\aaa.txt";
char *buf="e:\\aaa.txt";
handle=fopen(buf,"r");
if(!handle)
perror("can not open this file\n");
else
printf("you have opened this file successfully!\n");
fgets(con,100,handle);
printf("the content of file is:%s\n",con);
fclose(handle);
return 0;
}
主要介紹了fopen函數的第一個參數的使用,代碼里面說的已經很清楚了,其余類似fopen的函數的使用也一樣
摘要: linux文件權限的說明,和chmod命令的使用
閱讀全文
關于PATH的作用:
PATH說簡單點就是一個字符串變量,當輸入命令的時候LINUX會去查找PATH里面記錄的路徑。比如在根目錄/下可以輸入命令ls,在/usr目錄下也可以輸入ls,但其實ls這個命令根本不在這個兩個目錄下,事實上當你輸入命令的時候LINUX會去/bin,/usr/bin,/sbin等目錄下面去找你此時輸入的命令,而PATH的值恰恰就是/bin:/sbin:/usr/bin:……。其中的冒號使目錄與目錄之間隔開。
關于新增自定義路徑:
現在假設你新安裝了一個命令在/usr/locar/new/bin下面,而你又想像ls一樣在任何地方都使用這個命令,你就需要修改環境變量PATH了,準確的說就是給PATH增加一個值/usr/locar/new/bin。你只需要一行bash命令export PATH=$PATH:/usr/locar/new/bin。這條命令的意思太清楚不過了,使PATH自增:/usr/locar/new/bin,既PATH=PATH+":/usr/locar/new/bin";通常的做法是把這行bash命令寫到/root/.bashrc的末尾,然后當你重新登陸LINUX的時候(應該是linux啟動時就會執行這個文件),新的默認路徑就添加進去了。當然這里你直接用source /root/.bashrc執行這個文件重新登陸了。你可以用echo $PATH命令查看PATH的值。
關于刪除自定義路徑:
當某天你發現你新增的路徑/usr/locar/new/bin已經沒用了的話,你可以修改/root/.bashrc文件里面你新增的路徑。或者你可以修改/etc/profile文件刪除你不需要的路徑.
一般來說,配置交叉編譯工具鏈的時候需要指定編譯工具的路徑,此時就需要設置環境變量。例如我的mips-linux-gcc編譯器在“/opt/au1200_rm/build_tools/bin”目錄下,build_tools就是我的編譯工具,則有如下三種方法來設置環境變量:
--------------------------------------------
臨時環境變量(重啟后消失)
-----------------------------------------------------
1、直接用export命令:
#export PATH=$PATH:/opt/au1200_rm/build_tools/bin
查看是否已經設好,可用命令export查看:
[root@localhost bin]# export
declare -x BASH_ENV="/root/.bashrc"
declare -x G_BROKEN_FILENAMES="1"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="localhost.localdomain"
declare -x INPUTRC="/etc/inputrc"
declare -x LANG="zh_CN.GB18030"
declare -x LANGUAGE="zh_CN.GB18030:zh_CN.GB2312:zh_CN"
declare -x LESSOPEN="|/usr/bin/lesspipe.sh %s"
declare -x LOGNAME="root"
declare -x LS_COLORS="no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:"
declare -x MAIL="/var/spool/mail/root"
declare -x OLDPWD="/opt/au1200_rm/build_tools"
declare -x PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin:/opt/au1200_rm/build_tools/bin"
declare -x PWD="/opt/au1200_rm/build_tools/bin"
declare -x SHELL="/bin/bash"
declare -x SHLVL="1"
declare -x SSH_ASKPASS="/usr/libexec/openssh/gnome-ssh-askpass"
declare -x SSH_AUTH_SOCK="/tmp/ssh-XX3LKWhz/agent.4242"
declare -x SSH_CLIENT="10.3.37.152 2236 22"
declare -x SSH_CONNECTION="10.3.37.152 2236 10.3.37.186 22"
declare -x SSH_TTY="/dev/pts/2"
declare -x TERM="linux"
declare -x USER="root"
declare -x USERNAME="root"
可以看到,環境變量已經設好,PATH里面已經有了我要加的編譯器的路徑。
里去操作了。
永久環境變量
--------------------------------------------------------
2、修改profile文件:
所有用戶(不安全)
修 改/etc/profile(對所有用戶都是有效的)
#vi /etc/profile
在里面加入:
export PATH="$PATH:/opt/au1200_rm/build_tools/bin"
3. 修改.bashrc文件:
# vi /~/.bashrc
(單獨用戶)
修改~/.bashrc文件。 htt(74)p://www.icwin.net/bbs http://www.wantso.com (每個用戶目錄下都有,ls -all)
cd ~
vi .bashrc
在里面加入:
export PATH="$PATH:/opt/au1200_rm/build_tools/bin"
后兩種方法一般需要重新注銷系統才能生效,最后可以通過echo命令測試一下:
# echo $PATH
看看輸出里面是不是已經有了/my_new_path這個路徑了。
-----------------------------------------------------------------------------------------------------------------------
“/bin”、“/sbin”、“/usr/bin”、“/usr/sbin”、“/usr/local/bin”等路徑已經在系統環境變量中了,如果可執行文件在這幾個標準位置,在終端命令行輸入該軟件可執行文件的文件名和參數(如果需要參數),回車即可。
如果不在標準位置,文件名前面需要加上完整的路徑。不過每次都這樣跑就太麻煩了,一個“一勞永逸”的辦法是把這個路徑加入環境變量。命令 “PATH=$PATH:路徑”可以把這個路徑加入環境變量,但是退出這個命令行就失效了。要想永久生效,需要把這行添加到環境變量文件里。有兩個文件可選:“/etc/profile”和用戶主目錄下的“.bash_profile”,“/etc/profile”對系統里所有用戶都有效,用戶主目錄下的“.bash_profile”只對這個用戶有效。
“PATH=$PATH:路徑1:路徑2:...:路徑n”,意思是可執行文件的路徑包括原先設定的路徑,也包括從“路徑1”到“路徑n”的所有路徑。當用戶輸入一個一串字符并按回車后,shell會依次在這些路徑里找對應的可執行文件并交給系統核心執行。那個“$PATH”表示原先設定的路徑仍然有效,注意不要漏掉。某些軟件可能還有“PATH”以外類型的環境變量需要添加,但方法與此相同,并且也需要注意“$”。
注意,與DOS/Window不同,UNIX類系統環境變量中路徑名用冒號分隔,不是分號。另外,軟件越裝越多,環境變量越添越多,為了避免造成混亂,建議所有語句都添加在文件結尾,按軟件的安裝順序添加。
格式如下():
# 軟件名-版本號
PATH=$PATH:路徑1:路徑2:...:路徑n
其他環境變量=$其他環境變量:...
在“profile”和“.bash_profile”中,“#”是注釋符號,寫在這里除了視覺分隔外沒有任何效果。
設置完畢,注銷并重新登錄,設置就生效了。如果不注銷,直接在shell里執行這些語句,也能生效,但是作用范圍只限于執行了這些語句的shell。
相關的環境變量生效后,就不必老跑到軟件的可執行文件目錄
條件編譯,有三種格式
1 #if 表達式
程序段1
#else
程序段2
#endif
很簡單,表達式為真編譯1,否則編譯2。
2 #ifdef 標識符
程序段1
#else
程序段2
#endif
如果標識符已用#define定義過,則為真編譯1,否則編譯2
3 和2的基本一致就是把ifdef換成ifndef。用法是為假編譯1,否則2
比如#include <stdio.h>
int main()
{
#ifdef _DEBUG
printf("hello world\n");
#else
printf("no debug");
#endif
return 0;
}
在linux用gcc編譯是,如果使用gcc -D_DEBUG -o main main.c。則就是說明定義過_DEBUG,運行結果是hello world。注意是-D選項,-D后面緊跟著標識符名字
如果使用:gcc -o main mian.c,怎說明沒有定義標識符,運行結果是no debug了。
當然,也可以直接再代碼里顯示寫上一句:#define _DEBUG,也能有相同效果。
宏的使用的核心,就是替換,換是最關鍵的。
1、不帶參數的宏定義
這是最簡單的了,比如#define PI 3.1415926
預編譯的時候,把代碼中的PI替換就行了。一般情況下宏名用大寫字母,不要在行末加分號。
2、帶參數的宏定義
不只是進行宏體的替換,還要進行參數的替換。
比如:#define MAX(x,y) (x>y)?x:y
宏展開的時候要將語句中宏名后面的括號內的實參代替形參。另外為了避免發生錯誤,凡是帶運算符的參數要用圓括號括起來。
3、不常見但是很重要的用法
(1)#define FUN(a) "a"
那么當輸入FUN(345)是,照樣會被替換成“a”,無論宏的實參是什么,都不會影響其被替換成"a"的命運。
也就是說,""內的字符不被當成形參,即使它和一模一樣。
(2)有參宏定義中#的用法
#define STR(str) #str
str前面的那個#用于把宏定義中的參數兩端加上字符串的""
比如代碼中有STR(my#name),那么在展開的時候被替換成"my#name"。
一般由任意字符都可以做形參,但以下情況會出錯:
STR())這樣,編譯器不會把“)”當成STR()的參數。
STR(,)同上,編譯器不會把“,”當成STR的參數。
STR(A,B)如果實參過多,則編譯器會把多余的參數舍去。(VC++2008為例)
STR((A,B))會被解讀為實參為:(A,B),而不是被解讀為兩個實參,第一個是(A第二個是B)。
(3) 有參宏定義中##的用法
#define WIDE(str) L##str
則會將形參str的前面加上L
比如:WIDE("abc")就會被替換成L"abc"
如果有#define FUN(a,b) vo##a##b()
那么FUN(id ma,in)會被替換成void main()
再比如:
#define s5(a) supper_ ## a
#include <stdio.h>
void supper_printf(const char* p )
{
printf("this is supper printf:\n%s\n",a);
}
int main()
{
s5(printf)("hello owrld");//就是調用函數supper_printf.
return 0;
}
(4) 多行宏定義:
#define doit(m,n) for(int i=0;i<(n);++i)\
{\
m+=i;\
}
關鍵是要在每一個換行的時候加上一個 "\ " ,最后一行不用加。這樣使用的時候就可以用doit(m,n)來代替for循環結構了。
還是先看看csapp上的解釋:并發(concurrency)是指一個通用上的概念,指一個同時具有多個活動的系統;并行(parallelism)指的是用并發使一個系統運行得更快。
百度的解釋:并發, 在
操作系統中,是指一個時間段中有幾個程序都處于已啟動運行到運行完畢之間,且這幾個程序都是在同一個
處理機上運行,但任一個時刻點上只有一個程序在處理機上運行。也就是實際上,并發使指的在邏輯上,宏觀上,一個計算機能夠同時執行多個任務多個程序,但是微觀上看,在同一個時刻,只有一個程序在運行,但是由于處理器速度非常快的在幾個程序來回切換,讓我們覺得是好幾個程序同時在執行。
而并行則是真正的讓計算機在物理上同時執行多個活動。
舉個例子,媽媽(cpu)在上午10點后開始做家務(程序),首先是收拾房間,收拾完房間后,開始洗衣服,洗完衣服后開始做午飯,那么到中午12點,媽媽一共做了3件事情(程序),從宏觀上看,媽媽在一個上午的時間同時做了3個家務,但是實際上這三件事并不是同時做的。而如果媽媽這么選擇做家務:在收拾房間的同時,把衣服扔到洗衣機里讓洗衣機洗著,同時又讓電飯鍋蒸著米飯,等媽媽收拾完房間的同時衣服也洗好了,飯也做熟了。三件事情等于是真正上的同時執行的,這就是并行。很明顯我們會發現,并行的速度要遠遠快于并發。
當然并發和并行的具體實現遠遠很復雜,這只是先從概念上區分開并發和并行。
先寫出將要解釋的哪幾對概念:
程序、進程和線程
并發和并行
多線程和超線程
單核和多核。(
必須先咒罵一句,以下內容其實是第二遍寫了,在第一次發表的時候,沒有發表成功,結果全都沒有了,還得重新寫一遍,第一次寫的內容其實很多,第二次是在沒有心思寫太多了,只寫主要的了,TMD....)
程序是死的,只是安裝到你的電腦上的一堆文件而已,你不允許它,它就靜靜躺在那里,什么都不做。進程:很專業的解釋是,操作系統對一個運行的程序的一種抽象(CSAPP)。果然是很抽象的,抽象的基本不懂。進程就是代表程序在電腦里運行的,每一個程序至少有一個進程,進程是進程是一個具有一定獨立功能的程序關于某個數據集合的一次運行活動。當賦予死的程序以生命時,它就成了一個活動的實體,稱之為進程。每一個進程運行后,都會向cpu索要相應的系統資源,都會有自己一定的地址空間,在這空間里會存放文本區域(text region)、數據區域(data region)和
堆棧(stack region)。文本區域存儲處理器執行的代碼;數據區域存儲變量和進程執行期間使用的動態分配的內存;堆棧區域存儲著活動過程調用的指令和本地變量。線程,線程,有時被稱為
輕量級進程(Lightweight Process,LWP),是程序執行流的最小
單元。每一個進程都至少有一個主線程,進程向系統申請一段地址空間,而線程并不擁有專屬于自己的地址空間,每個線程都只擁有一點點必不可少的資源,進程中所有的線程共享進程的資源。線程一個創建和撤銷另外一個線程。線程其實才是真正利用cpu的單位,它是能獨立運行的基本單位,也是獨立調度和分派的單位。可以這么認為,進程向cpu申請了地址空間后,然后把真正要做的工作全部交給了線程去做,但是線程使用的資源是由進程代表申請的。
拿一個c程序舉例子來說明下進程和線程的關系,一個c程序只有一個主函數,main函數,但是可以擁有其他很多子函數,main函數是c程序運行的切入點,通過main函數可以調用其他子函數,main函數和其他子函數共享全局變量,也可以相互之間很方便的傳遞數據。這里,可以把進程看成一個c程序,一個進程也只擁有一個主線程,主線程就是相當于main函數,線程之間共享數據,也可以相互很方便的傳遞數據。
再舉一個更生動的數據。說:
一堆肉,是死的,什么都做不了,但是一堆肉組成了一個人,人是活的有生命的,人又由很多器官組成,當人想要做什么事情的時候,其實是由大腦這個器官調配其余器官來真正做的。可以說人在這個社會上占有一定的資源,但是真正使用這些資源的是器官,但是我們不能說器官占有這些資源。這里,程序就是一堆肉,進程就是一個人,線程就是器官,其中主線程是大腦。
這些概念都有所了解,但是要想完全說清楚很難了,等我逐一弄懂,并且確定自己的了解是正確的后,我會貼出來的。
WAITING...
首先看名字不要太多誤會,我說的意思是不要看《深入理解計算機系統》(裘奕利雷迎春翻譯),但是《computer system a programmer‘s perspective》這本書是一定要看的。
有人說這兩本書不是一樣嘛,一個英文原版一個中文翻譯版。
非也!
當初自恃英文水平不是很高,不敢看英文原版的,于是乎買了本中文版。看這本書也有段時間了,現在是越看越窩火,翻譯的真的真的是太差勁了。
先從翻譯的這個中文破名字說起,英文名字直接翻譯漢語大概應該是:以一個程序員的角度來看計算機系統。不知道怎么就給翻譯成了深入理解計算機系統。我想百分之90的人們看到這個名字,都不會聯系到實際的書的內容。
翻開書正文內容第一頁——出版者的話,第六個字就很明顯的錯了,也不知道是翻譯的錯誤或者說是作者語文水平太差或者說是印刷錯誤(這個錯誤還勉強可以接受吧),由此管中窺豹,可見翻譯者或者出版社的態度了,至少不是十分認真了,書的僅僅第六個字就弄錯了。
再談,書的內容的翻譯,我想如果要是季羨林大師再世的話,僅從漢語的角度看看這本中文書(雖然我可以基本肯定大師不太懂計算機系統和c吧),非得氣死。從我一個工科學生對語文的了解,就可以發現通篇的漢語語法錯誤,不是缺主謂賓就是缺定狀補,有的錯誤憑著多年對漢語的應用可以自己理解過來,但是通篇很多的錯誤實在讓人受不了,還有更過分的是對一些專業術語的翻譯,從漢語表面的意思實在聯想不到和這個術語的實際意義有啥相關系。再有就是很多很多的超長句子,一個句子有太多的修辭詞定語狀語,我說你丫的翻譯者就不能把長句分成幾個短句啊!
本來有些內容就不是很好理解,很晦澀,再加上這個糟糕的翻譯,在想深入理解書中的內容時,真是太痛苦了!我真有一種想痛罵的沖動!!
以后再買一些英文技術書籍時,堅決只買英文版的,雖然開始看時會慢些,需要對著個英文翻譯軟件查不認識的單詞,但后期肯定會越來越好的。
強烈建議大家學這書的內容時,買英文版的,至少不要買這一版的中文版!!
另外再點名另外一本中文翻譯的書《數據結構和算法分析:C++描述》,翻譯的更差勁!
點名表揚一本書《C++ primer》,這本書的中文翻譯我自認為在我看到的眾多翻譯過來的書中是最好的了!
第一遍看這本書的時候,稍微掃了一遍這個內容,當時看起來有時生硬,不是很懂,等于跳了過去了。現在再看,感覺很有用,也基本能看明白了。說個題外話,有時候看有些內容,第一次看到的時候,覺得很難理解很難理解,就是反復看好幾遍也理解不了。那么不妨就放下這段內容,也許你學過后面的內容的后,有天你再返回來看當初不懂的,就豁然開朗了,學習這本c++primer的過程中,真的有太多的這種體會了。
開始正題:
#define 指示的接受后面的名字,并把這個名字定義為預處理器變量,常用大寫。
#ifndef 字面意思就是if not define 如果沒有定義。就是如果后面的名字沒有被定義成預處理器變量,那么這句話后所有的程序都將被執行,直到遇見#endif
說明具體用法和意義。
假如我自己寫了兩個頭文件one.h,和two.h。其中one.h包括的是一個類的定義;two.h由于也要用到這個類,所以這個頭文件里面必然要有一行程序:#include“one.h”。
而我們的主程序里面,開始必然要把我們自己定義的頭文件給加進去,必然應該有兩行程序:#include“one.h”和#include“two.h”,這樣實際上one.h這個頭文件被包含了兩次,那個類的也相當于定義了兩次,必然編譯時會出現錯誤,為了解決這個問題。在one.h里應該加入這么一段程序:
#ifndef ONE
#define ONE
//這里應是one.h里面本來應該有的代碼程序
#endif
這樣這個頭文件在主程序處理時只會被處理一次。因為:當主程序首先碰到這句::#include“one.h,時,由于是第一次處理one頭文件,ONE這個預處理器變量還沒有定義呢,所以會執行#define ONE這個語句,ONE變量被定義了,頭文件one中的代碼也會被執行了。當主程序碰到這句:#include“two.h”,由于two頭文件中,也有這么一句:#include“one.h”,然后程序就會再次進入到one這個頭文件中執行,這是由于ONE這個變量在第一次執行one這個頭文件時已經被定義了,所以#ifndef ONE判斷失敗,不會執行后續的代碼了,也就不會在執行one頭文件中實際有用的代碼了。這樣保證了頭文件只會被處理一次。
因此應該在自己編寫的每個頭文件中都加上保護符,避免頭文件被多次包含。