讀《程序員的自我修養》有感git
花了幾天時間,研讀了《程序員的自我修養——連接、裝載與庫》。我的感受它在操做系統的底層機制和運行原理可謂是一本好書。惋惜我的修爲不夠、根底太淺,對Linux一樣不熟悉。等之後有積累了再來回讀一番。程序員
做者在序言裏這樣提出:計算機思想其實都是相通的,由於它們的核心思想是穩定不變的。這在我看來很大程度上是因爲底層架構決定的,現行的計算機大多仍是馮·諾依曼架構(量子計算機還有待成熟),所以萬變不離其宗。算法
做者是個極愛鑽研的人,到處可見一斑。對於最簡單的入門程序「hello world」,做者對其提出了一連串的問題,這讓我大感意外。「C語言程序爲何要被編譯後才能運行?」、「編譯過程當中發生了什麼?」、「不一樣狀況下的編譯結果是否相同」。如此簡單的程序背後每每蘊含着複雜機制,若是單單是做爲一個編譯器的使用者,天然沒必要考慮這一切。可是若是但願進一步對此有了解,乃至可以創造出更好的機制,那麼這都是不可或缺的。從「預處理」、「編譯」到「彙編」再到「連接」,編譯器開始爲咱們所理解。原來「#define」,「#include」在一開始就會被展開和替代。而在掃描過程當中進行源代碼的生成,以後再進行一步步的工做。於此咱們能夠見微知著,一部分原來有些強硬的規範其實有着深入的內涵。例如宏語句使用時的注意事項(儘可能加個括號),調試時「莫名其妙」被省略的變量(編譯器提供的代碼優化),開數組的時候全局變量每每能比局部變量分配更大的空間(堆棧與靜態存儲的不一樣)。這些小細節不是空穴來風、而是底層架構在上層的具象反映。而掌握底層架構,可以使咱們更加精細地利用計算機的功能。編程
計算機科學有至關一部分須要依賴於自個人實踐。做者爲了瞭解操做系統及裝載等這些關鍵的技術,他從頭寫了一個很小的內核、裝載器及一個簡單的運行庫,作成了一個簡單但較爲完備的操做系統。儘管這些沒什麼直接收益(讓GPA增長是不可能的,讓本身發paper也是不可能的……),可是能夠從中舉一反三。我的做業時寫簡單的hash的時候和大數組搜索算法時由於好久不動,致使碼了好久,因此說僅僅是領悟思想是不夠的,還要付諸實踐。看這本書的時候看到了語法樹部分,感受它比數據結構課上所講的中序表達式二叉樹很爲類似,就順手寫了個解釋C語言代碼(極簡版)的代碼,中間參考了別人的一些想法(主要是《C專家編程》),完成後讓本身很有所得(儘管這無法計入成績(*^_^*))。數組
1 #include"stdio.h" 2 #include"string.h" 3 #include"ctype.h" 4 #include"stdlib.h" 5 6 #define MAXTOKENS 100 //設置語句中標識符的最大數量100 7 #define MAXTOKENLEN 64 //設置標識符的最大長度64 8 9 enum type_tag {IDENTIFIER,QUALIFIER,TYPE}; //IDENTIFIER=0,QUALIFIER=1,TYPE=2 10 11 struct token //結構體:標識符(token) 12 { 13 char type; //type:數據類型 14 char string[MAXTOKENLEN]; //string[MAXTOKENLEN]:存儲標識符名稱的數組 15 }; 16 17 int top=-1; 18 struct token stack[MAXTOKENS]; //stack[]:存儲整句語句的標識符的數組(堆棧) 19 struct token these; //these:臨時存儲單個標識符的變量 20 21 #define pop stack[top--] 22 #define push(s) stack[++top] = s //push(s):將變量s壓入stack數組頂端 23 24 enum type_tag classify_string(void) /*推斷標識符的類型*/ 25 { 26 char *s = these.string; /*用指針s代替these的string數組使用(簡潔)*/ 27 if(!strcmp(s,"const")) //若是string中是"const" 28 { 29 strcpy(s,"read-only"); //將s中的"const"翻譯爲"read-only" 30 return(QUALIFIER); 31 } 32 if(!strcmp(s,"volatile")) 33 return(QUALIFIER); 34 if(!strcmp(s,"void")) //下面一系列if判斷,返回type:數據類型說明 35 return(TYPE); 36 if(!strcmp(s,"char")) 37 return(TYPE); 38 if(!strcmp(s,"signed")) 39 return(TYPE); 40 if(!strcmp(s,"unsigned")) 41 return(TYPE); 42 if(!strcmp(s,"short")) 43 return(TYPE); 44 if(!strcmp(s,"int")) 45 return(TYPE); 46 if(!strcmp(s,"long")) 47 return(TYPE); 48 if(!strcmp(s,"float")) 49 return(TYPE); 50 if(!strcmp(s,"double")) 51 return(TYPE); 52 if(!strcmp(s,"struct")) 53 return(TYPE); 54 if(!strcmp(s,"union")) 55 return(TYPE); 56 if(!strcmp(s,"enum")) 57 return(TYPE); 58 return(IDENTIFIER); 59 } 60 61 void gettoken(void) /*讀取下一個標記到"these"*/ 62 { 63 char *p = these.string; 64 65 /*跳過空白字符*/ 66 while((*p = getchar()) == ' '); 67 68 if(isalnum(*p)) /*輸入的字符以A-Z,0-9開頭*/ 69 { 70 while(isalnum(*++p = getchar())); 71 ungetc(*p,stdin); 72 *p='\0'; 73 these.type = classify_string(); 74 return; 75 } 76 77 if(*p == '*') 78 { 79 strcpy(these.string,"pointer to"); 80 these.type = '*'; 81 return; 82 } 83 these.string[1] = '\0'; 84 these.type = *p; 85 return; 86 } 87 88 /*理解全部分析過程的代碼段*/ 89 void read_to_first_identifier(void) 90 { 91 gettoken(); 92 while(these.type != IDENTIFIER) 93 { 94 push(these); 95 gettoken(); 96 } 97 printf("%s is ", these.string); 98 gettoken(); 99 return; 100 } 101 102 void deal_with_arrays(void) 103 { 104 while(these.type == '[') 105 { 106 printf("array "); 107 gettoken(); /*數字或']'*/ 108 if(isdigit(these.string[0])) 109 { 110 printf("0..%d ",atoi(these.string)-1); 111 gettoken(); /*讀取']'*/ 112 } 113 gettoken(); /*讀取']'以後的一個標記*/ 114 printf("of "); 115 } 116 return; 117 } 118 119 void deal_with_function_args(void) 120 { 121 while(these.type !=')') 122 { 123 gettoken(); 124 } 125 gettoken(); 126 printf("function returning "); 127 return; 128 } 129 130 void deal_with_pointers(void) 131 { 132 while(stack[top].type == '*') 133 { 134 printf("%s ", pop.string); 135 } 136 return; 137 } 138 139 void deal_with_declarator(void) /*處理標識符以後可能存在的數組或函數*/ 140 { 141 switch(these.type) 142 { 143 case '[' : deal_with_arrays();break; 144 case '(' : deal_with_function_args(); 145 } 146 147 deal_with_pointers(); 148 149 while(top >= 0) /*處理在讀入到標識符以前壓入堆棧中的符號*/ 150 { 151 if(stack[top].type == '(') 152 { 153 pop; 154 gettoken(); 155 deal_with_declarator(); 156 } 157 else 158 { 159 printf("%s ", pop.string); 160 } 161 } 162 return; 163 } 164 165 int main(void) 166 { 167 read_to_first_identifier(); /*將標記壓入堆棧中,直到碰見標識符*/ 168 deal_with_declarator(); 169 printf("\n"); 170 return(0); 171 }
這本書感受往後還要再重讀一次,可能感悟會更深一些。不過在一週時間內在這本書上搜颳了一些東西,也算是不枉一讀了,幸甚幸甚。數據結構