第十章 使用變數的一般問題
General Issues in Using Variables
10.1 資料認知
Data Literacy
資料認知測試
The Data Literacy Test
熟悉1分,知道又不太確定0.5分,不知道沒聽過0分(依繁體中文版順序)
______ abstract data type | ______ heap | ______ retroactive synapse |
______ array | ______ index | ______ referential integrity |
______ bitmap | ______ integer | ______ stack |
______ boolean variable | ______ linked list | ______ string |
______ B-tree | ______ named constant | ______ structured variable |
______ character variable | ______ literal | ______ tree |
______ container class | ______ local variable | ______ typedef |
______ double precision | ______ lookup table | ______ union |
______ elongated stream | ______ member data | ______ value chain |
______ enumerated type | ______ pointer | ______ variant |
______ floating point | ______ private | ______ Total Score |
分數分析....
0-4 新手,
15-19 中階,
20-24 專業,
25-29 比作者更厲害~可以出書了,
30~32....(買這本書就知道了!)
資料型別的其它資源
Additional Resources on Data Types
Cormen, H. Thomas, Charles E. Leiserson, Ronald L. Rivest. Introduction to Algorithms. New York: McGraw Hill. 1990.
Sedgewick, Robert. Algorithms in C++, Part 5, 3d ed. Boston, Mass.: Addison-Wesley, 2002.
Sedgewick, Robert. Algorithms in C++, Parts 1-4, 3d ed. Boston, Mass.:Addison-Wesley, 1998.
10.2 輕鬆掌握變數宣告
Making Variable Declarations Easy
隱含宣告Implicit Declarations
定義: 不用自己先宣告變數,compilier會幫你宣告。
關閉隱含宣告
宣告所有變數
使用命名慣例
檢查變數名稱
10.3 初始化變數的原則
Guidelines for Initializing Variables
初始化會出問題的原因在於:
- 未賦值
- 值已過期
- 變數一部份被賦值,一部份沒有
除錯指標的錯誤,比其它錯誤更困難。
為避免上述的問題,採用下列幾種原則
- 宣告時初始化
- 靠近第一次使用變數前,就初始化
- 不支援宣告時初始化的語言
- 靠近第一次使用變數前,就宣告及初始化←最理想的
- c語言不支援
- 在可以的情況之下,加上const或final
- 限制變數使用權限,會降低出錯的機會
- 注意計數索引變數和累加索引變數
- 使用前reset
- 建構函式中初始化類別的成員資料
- construct中初始化類別資料。
- 在construct中new的空間,務必在deconstruct中delete掉。
- 確認重新初始化的需要
- 迴圈使用變數多次
- 常式呼叫之間保留其值
- 初始化const變數一次
- 用可執行程式碼來初始化變數;初始化含可執行程式碼的變數
- 初始化常數的function: Startup()
- 其它一般的function: AnyPossibleNames()
- 在此若需要常數(只需初始化一次就永遠不需要修改的變數)就放在Startup()並且在程式執行中,確定呼叫一次
- 其它變數則放在AnyPossibleNames(),在需要呼叫該函式時再初始化。
- 使用自動初始化所有變數的編譯器設定
- 打開compilier的自動初始化變數功能,壞處在提高code依賴專案設定的程度以及培養程式設計人員檢查初始化的習慣。
- 利用編譯器警告訊息
- 警告你未初始化(未使用)的變數
- 檢查輸入參數的有效性
- 利用assert()
- 使用記憶體存取檢查程式,檢查錯誤的指標
- 構買memory-access checker程式
- 在程式一開始的地方初始化工作記憶體(working memory)
- 使用預先程式化記憶體填充工具
- 填入0
- 填入0xCC
- 填入0xDEADBEEF //11011110101011011011111011101111
0012FF44 EF BE AD DE - 如果你正使用記憶體填充工具,可以偶爾改變一下填充的值,可以找到「背景環境保持不變的情況下」無法察覺的錯誤。
- 開啟程式時讓程式初始化working memory,這是不同於前兩項曝露缺陷的方式,而是一種要隱藏缺陷的方式。避免程式不會因為記憶體初始值的隨機性而受到影響。
-
確保未初始化的指標指向記憶體底部,方便偵測出誤用未初始化指標的情況。
-
對於x86的處理器來說,填入0xCC是不錯的數值,它是一個中斷點int 03h的mechine code
71: ptr = (int*)204; //0xcc = 11001100
00405308 mov dword ptr [ebp-4],0CCh
在debug tool中執行時,執行一段數據,而不是執行程式碼時就會進入中斷點。
容易從memory dump的訊息中識別出來,而且很少有合法的用途
- 因為容易在debug tool工具上看出來
10.4 範圍
Scope
區域化變數參考
Localize References to Variables
定義Span:span = 第一次使用的行數 - 最後一次使用的行數 - 1
Java Example of Variable Span
a = 0;
b = 0;
c = 0;
a = b + c;
span: a=2, b=1, c=0Java Example of Spans of One and Zero
a = 0;
b = 0;
c = 0;
b = a + 1;
b = b / c;
span: 第一次b=1, 第二次b=0, avgSpan b=0.5span愈小,可讓讀程式碼的讀者注意小區域的程式,不會跳來跳去的,可增加可讀性。
盡量縮短變數的「壽命」
Keep Variables Live for As Short a Time As Possible
存活時間,在這我稱為「壽命」(live time)定義:
live time = 第一次使用的行數 - 最後一次使用的行數 + 1
測量變數的生存時間
Measuring the Live Time of a Variable
用以上的定義算出平均值
減少Scop的一般原則
General Guidelines for Minimizing Scope
在迴圈開始之前再去初始化迴圈內使用的變數,而不是在副程式一開始初始化變數使用之前再賦值
把相關的陳述式放在一起
把相關的陳述式提取成副程式
以最小權限為最初宣告,需要時再打開權限
最小化Scop的心得
Comments on Minimizing Scope
「便利性」哲學與「智慧管理能力」哲學之間的差異便利性: 全域變數
智慧管理能力: 權限少、限制多、壽命短的區域變數
10.5 持續性
Persistence
「持續性」就是span的另一個說法原文:“Persistence”is another word for the life span of a piece of data.
- 在副程式中:從 { 到 }
- 在指定的程式段:從 new 到 delete
- 在整個程式中:從 main 到 return EXIT_SUCCESS;
- 直到永遠:存到檔案中。
- 使用debug程式碼或assert()
- 賦上不合理的值,指標賦值0或null(音同now)
- 使用變數,在進出副程式之後,要假設變數失去上次賦予的值(不適用於static變數)
- 養成使用變數前檢查是否宣告和賦值的習慣
10.6 繫結時間
Binding Time
定義:「繫結時間」:變數與變數的值真正聯繫在一起的時間。(參考資料)
也就是「賦值的時間點」。
- 編碼時(使用magic number、hard code)
- 編譯時(使用const)
- 來自檔案
- 生成物件(creat時,不同於初始化)
- 即時(重畫視窗的值)
10.7 資料型別與控制結構的關係
Relationship Between Data Types and Control Structures
- 循序陳述式
- 選擇性陳述式
- 重覆迴圈
10.8 為變數指定單一用途
Using Each Variable for Exactly One Purpose
遠離為一個變數賦序多種職責的奇技淫巧。
每個變數只用在單一用途
一個變數,重覆使用,常發生在臨時變數身上,通常是temp、a, b, c, kk或x的這種無意義的變數身上// Compute roots of a quadratic equation.
// This code assumes that (b*b-4*a*c) is positive.
temp = Sqrt( b*b - 4*a*c );
root[O] = ( -b + temp ) / ( 2 * a );
root[1] = ( -b - temp ) / ( 2 * a );
...
// swap the roots
temp = root[0];
root[0] = root[1];
root[1] = temp;
這例子中的 temp就用在Sqrt()又用在swap中。事實上沒關係的兩個行為,就會被誤以為有關係
為提昇可讀性,可以改成下面的寫法
// Compute roots of a quadratic equation.
// This code assumes that (b*b-4*a*c) is positive.
discriminant = Sqrt( b*b - 4*a*c );
root[0] = ( -b + discriminant ) / ( 2 * a );
root[1] = ( -b - discriminant ) / ( 2 * a );
...
// swap the roots
oldRoot = root[0];
root[0] = root[1];
root[1] = oldRoot;
避免變數有隱喻
下面有三種要避免使用的例子- pageCount, >= 0代表列印的紙張數量,= -1,代表發生錯誤。
- customerId, 1....2...3...代表正常的,500000+1....500000+2...500000+3..代表拖欠帳號的號碼。
- bytesWritten, >= 0代表文件的byte數,< 0代表輸出的磁碟機代號。
沒有留言:
張貼留言
(什麼是留言欄訊息?)