10 things you can do to write better code 写好代码的十个秘诀
DESCRIPTION
10 Things You Can Do To Write Better Code 写好代码的十个秘诀. 林斌 Development Manager Microsoft Research, China. 一流代码. 一流代码的特性. 鲁棒 - S olid and Robust Code 简洁 - Maintainable and Simple Code 高效 - Fast Code 简短 - Small Code 共享 - Re-usable Code 可测试 - Testable Code 可移植 - Portable Code. - PowerPoint PPT PresentationTRANSCRIPT
![Page 1: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/1.jpg)
1
10 Things You Can Do To Write Better Code
写好代码的十个秘诀
林斌Development Manager
Microsoft Research, China
![Page 2: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/2.jpg)
2
一流代码的特性
• 鲁棒 - Solid and Robust Code
• 简洁 - Maintainable and Simple Code
• 高效 - Fast Code
• 简短 - Small Code
• 共享 - Re-usable Code
• 可测试 - Testable Code
• 可移植 - Portable Code
一流代码
![Page 3: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/3.jpg)
3
Why is this code bad?
void MyGirlFriendFunc(CORP_DATA InputRec, int CrntQtr, EMP_DATA EmpRec, float EstimRevenue, float YTDRevenue, int ScreenX, int ScreenY, COLOR_TYPE newColor, COLOR_TYPE PrevColor, STATUS_TYPE status, int ExpenseType)
{ int i;for (i=1; i<100; i++) InputRec.revenue[i] = 0;
for (i=1; i<100; i++)InputRec.expense[i]= CorpExpense[i];
UpdateCorpDatabase(EmpRec);EstimRevenue =YTDRevenue*4.0/(float)CrntQtr;
NewColor = PreColor;Status = Success;if (ExpenseType== 1) for (i=1;i<12;i++) Profit[i] = Revenue[i]-Expense.Type1[i];
else if (ExpenseType == 2) Profit[i] = Revenue[i] - Expense.Type2[i];
else if (ExpenseType==3) { Profit[i] =Revenue[i] -Expense.Type3[i];
}
![Page 4: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/4.jpg)
4
Why is this code bad?
void MyGirlFriendFunc(CORP_DATA InputRec, int CrntQtr, EMP_DATA EmpRec, float EstimRevenue, float YTDRevenue, int ScreenX, int ScreenY, COLOR_TYPE newColor, COLOR_TYPE PrevColor, STATUS_TYPE status, int ExpenseType)
{ int i;for (i=1; i<100; i++) InputRec.revenue[i] = 0;
for (i=1; i<100; i++)InputRec.expense[i]= CorpExpense[i];
UpdateCorpDatabase(EmpRec);EstimRevenue =YTDRevenue*4.0/(float)CrntQtr;
NewColor = PreColor;Status = Success;if (ExpenseType== 1) for (i=1;i<12;i++) Profit[i] = Revenue[i]-Expense.Type1[i];
else if (ExpenseType == 2) Profit[i] = Revenue[i] - Expense.Type2[i];
else if (ExpenseType==3) { Profit[i] =Revenue[i] -Expense.Type3[i];
}
![Page 5: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/5.jpg)
5
Because…
• Bad function name – Maintainability• Crash if CrntQtr equals 0 – Robustness• No comments – Maintainability• Unnecessary for loop – Performance• The function has no single purpose –
Reusability• Bad layout – Simplicity & Maintainability• None testable if ExpenseType is 1 – Testability• Many more: too many arguments, abuse usage
of 100, 4.0, etc, un-use parameters, none-documented parameters…
![Page 6: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/6.jpg)
6
代码高手十大秘诀
1. 集百家之长 , 归我所用 - Follow Basic Coding Style
2. 取个好名字 - Use Naming Conventions
3. 凌波微步 , 未必摔跤 - Evil goto’s? Maybe Not…
4. 先发制人 , 后发制于人 - Practice Defensive Coding
5. 见招拆招 , 滴水不漏 - Handle The Error Cases: They Will Occur!
![Page 7: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/7.jpg)
7
代码高手十大秘诀 (Cont.)
6. 熟习剑法刀术 , 所向无敌 - Learn Win32 API Seriously
7. 双手互搏 , 无坚不摧 - Test, but don’t stop there
8. 活用段言 - Use, don’t abuse, assertions
9. 草木皆兵 , 不可大意 - Avoid Assumptions
10.最高境界 , 无招胜有招 - Stop writing so much code
![Page 8: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/8.jpg)
8
• Your code may outlive you or your memory!• Think about the maintainer• Comment your code
– File Header– Function Header– Inline Commenting
• Pick a good name for your functions and variables• Set Tab/Indent to 4 characters• Align your code!• Less arguments
1. 集百家之长 , 归我所用 - Follow Basic Coding Style
![Page 9: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/9.jpg)
9
Coding Style (Cont.)
• Use all uppercase with underscores for macro.#define MY_MACRO_NUMBER 100
• Declare all your variables at the start of function.• Avoid hard coding constant. Use enum or macro.
#define MY_MAX_LENGTH 1024
• User braces for one line codeIf (m_fInitialized) {
hr = S_OK;
}
• Limit the length of a single function
![Page 10: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/10.jpg)
10
Spot the defect
DWORD Status = NO_ERROR;
LPWSTR ptr;
Status = f( ..., &ptr );
if( Status isnot NO_ERROR or ptr is NULL ) goto cleanup;
![Page 11: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/11.jpg)
11
Spot the defect
DWORD Status = NO_ERROR;
LPWSTR ptr;
Status = f( ..., &ptr );
if( Status isnot NO_ERROR or ptr is NULL ) goto cleanup;
is??? isnot??? or???new C/C++ keywords? No.overloaded operators? No.just some confusing macros …
![Page 12: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/12.jpg)
12
A better version
DWORD Status = NO_ERROR;
LPWSTR ptr = NULL;
Status = f( ..., &ptr );
if( (Status != NO_ERROR) || (ptr == NULL) ) goto cleanup;
• Make your intent explicitUse existing language constructs
Everybody understands them
• Avoid future problems: Initializeparenthesize
![Page 13: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/13.jpg)
13
What’s the maximum length of a function?
• Look at this example
• Watch out for functions > 200 lines!
• Study in 1986 on IBM’s OS/360: the most error-prone routines => longer than 500 lines.
• Study in 1991 on 148,000-line of code: functions < 143 lines => 2.4 times less expensive to fix than longer functions.
Omsg_cxx.tlkOver 1400 lines!!!
![Page 14: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/14.jpg)
14
Look at these codes
• Let’s look at these codes from our own projects:– Small functions:– Larger functions:
• Then look at those from Windows 2000 source tree:– NT Kernel Mode Code:– NT User Mode CPP File:– NT User Mode Header File:
align_cpp.tlk
variable_cpp.tlk
Event_c.tlk
write_cpp.tlk
Write_h.tlk
![Page 15: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/15.jpg)
15
2. 取个好名字 - Use Naming Conventions
• Hungarian Notation– [Prefix]-BaseTag-Name
• Standard [Prefix]:p – A pointer. CHAR* psz;rg – An array. DWORD rgType[…];c – A count of items. DWORD cBook;h – A handle. HANDLE hFile;
• Standard “BaseTag”void -> v int -> iBOOL -> f UINT -> uiBYTE -> b CHAR -> chWCHAR -> wch ULONG -> ulLONG -> l DWORD -> dwHRESULT -> hr fn -> functionsz -> NULL str USHORT, SHORT, WORD -> w
• C++ member variables start with: m_• Global variables start with: g_
![Page 16: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/16.jpg)
16
Let’s try these…
• A flag indicates whether a C++ object has been initialized:• BOOL m_fInitialized;
• A Session ID:• DWORD dwSessionID;
• A ref count in a C++ object:• LONG m_cRef; // skip the ‘l’
• A Pointer to BYTE buffer:• BYTE* pbBuffer;
• A global logfile filename buffer:• CHAR g_szLogFile[MAX_PATH];
• A pointer to a global logfile:• CHAR* g_pszLogFile;
![Page 17: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/17.jpg)
17
3. 凌波微步 , 未必摔跤 - Evil goto’s? Maybe Not…
• Why goto is bad?– Creates unreadable code…– Causes compiler to generate non-optimal
code…
• Why goto is good?– Cleaner code– Single entry, single exit– Less duplicate code
![Page 18: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/18.jpg)
18
Spot the gotos…
START_LOOP:If (fStatusOk) { if (fDataAvaiable) { i = 10; goto MID_LOOP; } else { goto END_LOOP; }} else { for (I = 0; I < 100; I++) {MID_LOOP: // lots of code here … … } goto START_LOOP;}END_LOOP:
![Page 19: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/19.jpg)
19
BAD gotos!!!
START_LOOP:If (fStatusOk) { if (fDataAvaiable) { i = 10; goto MID_LOOP; } else { goto END_LOOP; }} else { for (I = 0; I < 100; I++) {MID_LOOP: // lots of code here … … } goto START_LOOP;}END_LOOP:
BAD!!!
![Page 20: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/20.jpg)
20
How about this one?
pszHisName = (CHAR*)malloc(256);
if (pszHisName == NULL) {
free(pszMyName);
free(pszHerName);
return hr;
}
free(pszMyName);
free(pszHerName);
free(pszHisName);
return hr;
}
HRESULT Init(){ pszMyName = (CHAR*)malloc(256); if (pszMyName == NULL) { return hr; } pszHerName = (CHAR*)malloc(256); if (pszHerName == NULL) { free(pszMyName); return hr; }
![Page 21: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/21.jpg)
21
Duplicate code…
pszHisName = (CHAR*)malloc(256);
if (pszHisName == NULL) {
free(pszMyName);
free(pszHerName);
return hr;
}
free(pszMyName);
free(pszHerName);
free(pszHisName);
return hr;
}
HRESULT Init(){ pszMyName = (CHAR*)malloc(256); if (pszMyName == NULL) { return hr; } pszHerName = (CHAR*)malloc(256); if (pszHerName == NULL) { free(pszMyName); return hr; }
![Page 22: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/22.jpg)
22
Harder to maintain…
pszHisName = (CHAR*)malloc(256);
if (pszHisName == NULL) {
free(pszMyName);
free(pszHerName);
free(pszItsName);
return hr;
}
free(pszMyName);
free(pszHerName);
free(pszHisName);
free(pszItsName);
return hr;
}
HRESULT Init(){ pszMyName = (CHAR*)malloc(256); if (pszMyName == NULL) { return hr; } pszHerName = (CHAR*)malloc(256); if (pszHerName == NULL) { free(pszMyName); return hr; } pszItsName = (CHAR*)malloc(256); if (pszItsName == NULL) { free(pszMyName); free(pszHerName); return hr; }
![Page 23: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/23.jpg)
23
How about this one?
… …
Exit:
if (pszMyName)
free(pszMyName);
if (pszHeName)
free(pszHeName);
if (pszHiName)
free(pszHiName);
return hr;
}
HRESULT Init(){ pszMyName =(CHAR*)malloc(…); if (pszMyName == NULL) goto Exit; pszHeName =(CHAR*)malloc(…); if (pszHeName == NULL) goto Exit; pszHiName =(CHAR*)malloc(…); if (pszHiName == NULL) goto Exit;
![Page 24: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/24.jpg)
24
Single entry, single exit. No duplicate code…
… …
Exit:
if (pszMyName)
free(pszMyName);
if (pszHeName)
free(pszHeName);
if (pszHiName)
free(pszHiName);
return hr;
}
HRESULT Init(){ pszMyName =(CHAR*)malloc(…); if (pszMyName == NULL) goto Exit; pszHeName =(CHAR*)malloc(…); if (pszHeName == NULL) goto Exit; pszHiName =(CHAR*)malloc(…); if (pszHiName == NULL) goto Exit;
![Page 25: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/25.jpg)
25
Easy to maintain…
… …
Exit:
if (pszMyName)
free(pszMyName);
if (pszHeName)
free(pszHeName);
if (pszItName)
free(pszItName);
if (pszHiName)
free(pszHiName);
return hr;
}
HRESULT Init(){ pszMyName =(CHAR*)malloc(…); if (pszMyName == NULL) goto Exit; pszHeName =(CHAR*)malloc(…); if (pszHeName == NULL) goto Exit; pszItName =(CHAR*)malloc(…); if (pszItName == NULL) goto Exit; pszHiName =(CHAR*)malloc(…); if (pszHiName == NULL) goto Exit;
![Page 26: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/26.jpg)
26
Use the following goto guidelines
• Single entry, single exit? – use goto
• Don’t use more than one goto labels
• Use goto’s that go forward, not backward
• Make sure a goto doesn’t create unreachable code
![Page 27: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/27.jpg)
27
4. 先发制人 , 后发制于人 - Practice Defensive Coding
• Initialize variables• Check return values• Keep it simples
– Usually, simplicity = performance
• Keep it clean– Multi-thread clean– Minimize casts
• Avoid miscalculations– Divide by Zero– Signed vs. Unsigned
![Page 28: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/28.jpg)
28
Spot the defect
HRESULT hr;
LPSTR str = (LPSTR)LocalAlloc(LPTR, size);
if (str){
... // process appropriately
hr = S_OK;
}
return hr;
![Page 29: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/29.jpg)
29
Spot the defect
HRESULT hr;
LPSTR str = (LPSTR)LocalAlloc(LPTR, size);
if (str){
... // process appropriately
hr = S_OK;
}
return hr;
Returning a random status on failure
![Page 30: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/30.jpg)
30
A better version???
HRESULT hr = S_OK;
LPSTR str = (LPSTR)LocalAlloc(LPTR, size);
if (str){
... // process appropriately
hr = S_OK;
}
return hr;
![Page 31: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/31.jpg)
31
Probably not
HRESULT hr = S_OK;
LPSTR str = (LPSTR)LocalAlloc(LPTR, size);
if (str){
... // process appropriately
hr = S_OK;
}
return hr;
Return success if nothing happened?• Think before you fix!
![Page 32: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/32.jpg)
32
A better version!
HRESULT hr = S_OK;
LPSTR str = (LPSTR)LocalAlloc(LPTR, size);
if (str){
... // process appropriately
hr = S_OK;
} else {
hr = E_OUTOFMEMORY;
}
return hr;
![Page 33: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/33.jpg)
33
Spot the detect
BOOL SomeProblem(USHORT x)
{
while (--x >= 0) {
[…]
}
return TRUE;
}
![Page 34: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/34.jpg)
34
Spot the detect
BOOL SomeProblem(USHORT x)
{
while (--x >= 0) {
[…]
}
return TRUE;
}
• Infinite loop! Unsigned never negative!
![Page 35: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/35.jpg)
35
Spot the detect
wcscpy(wcServerIpAdd, WinsAnsiToUnicode(cAddr, NULL));
Note: WinsAnsiToUnicode is a private API which allocates a new UNICODE string given an ANSI string.
![Page 36: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/36.jpg)
36
Spot the detect
wcscpy(wcServerIpAdd, WinsAnsiToUnicode(cAddr, NULL));
WinsAnsiToUnicode can return NULL … which will cause a program crash
WinsAnsiToUnicode can return allocated memory … which will cause a leak
![Page 37: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/37.jpg)
37
A better version
LPWSTR tmp;
tmp = WinsAnsiToUnicode(cAddr, NULL);
if (tmp != NULL) {
wcscpy(wcServerIpAdd, tmp);
WinsFreeMemory((PVOID)tmp);
} else {
return(ERROR_NOT_ENOUGH_MEMORY);
}
![Page 38: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/38.jpg)
38
5. 见招拆招 , 滴水不漏 - Handle The Error Cases: They Will Occur!
• Common examples:– Out of memory– Exceptions being thrown– Registry keys missing– Networks going down
• This is the hardest code to test …– … so it better be right!
• Don’t fail in C++ object constructor, you can’t detect it!
![Page 39: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/39.jpg)
39
Error cases (continued)
• In an error case, the code should– Recover gracefully
• Get to a consistent state• Clean up any resources it has allocated
– Let its caller know• Interface should define and document the behavior (return
status, throw exception)• Code should adhere to that definition
• What not to do– Ignore the error– Crash– Exit
![Page 40: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/40.jpg)
40
Spot the detect
CWInfFile::CWInfFile() {
m_plLines = new TPtrList(); // ...
m_plSections = new TPtrList(); // ...
m_ReadContext.posLine = m_plLines->end();
. . .
}
![Page 41: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/41.jpg)
41
Spot the detect
CWInfFile::CWInfFile() {
m_plLines = new TPtrList(); // ...
m_plSections = new TPtrList(); // ...
m_ReadContext.posLine = m_plLines->end();
. . .
}
MFC’s operator new throws an exception– … causing a leak when out of memory
![Page 42: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/42.jpg)
42
A better version?
CWInfFile::CWInfFile() {try { m_plLines = new TPtrList(); // ... m_plSections = new TPtrList(); // ... m_ReadContext.posLine = m_plLines->end(); . . .} catch ( . . . ) { if (m_plLines) delete m_plLines; if (m_plSections) delete m_plSections; }}
![Page 43: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/43.jpg)
43
No!
CWInfFile::CWInfFile() {try { m_plLines = new TPtrList(); // ... m_plSections = new TPtrList(); // ... m_ReadContext.posLine = m_plLines->end(); . . .} catch ( . . . ) { if (m_plLines) delete m_plLines; if (m_plSections) delete m_plSections; }}
Values may be uninitializedValues may be uninitialized Think before you fix!Think before you fix!
![Page 44: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/44.jpg)
44
A better version
CWInfFile::CWInfFile() : m_plLines(NULL), m_plSections(NULL) {
try {
m_plLines = new TPtrList(); // ...
m_plSections = new TPtrList(); // ...
m_ReadContext.posLine = m_plLines->end();
. . .
} catch ( . . . ) {
if (m_plLines) delete m_plLines;
if (m_plSections) delete m_plSections;
}
}
![Page 45: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/45.jpg)
45
But wait, there is more
CWInfFile::CWInfFile() : m_plLines(NULL), m_plSections(NULL) {
try {
m_plLines = new TPtrList(); // ...
m_plSections = new TPtrList(); // ...
m_ReadContext.posLine = m_plLines->end();
. . .
} catch ( . . . ) {
if (m_plLines) delete m_plLines;
if (m_plSections) delete m_plSections;
}
}
When not use MFC, When not use MFC, operator newoperator new may may return NULL…return NULL…
![Page 46: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/46.jpg)
46
Spot the defect
Class foo {
private:
CHAR* m_pszName;
DWORD m_cbName;
public:
foo(CHAR* pszName);
CHAR* GetName()
{return m_pszName;}
…
};
foo::foo(CHAR* pszName){ m_pszName = (BYTE*) malloc(NAME_LEN); if (m_pszName == NULL) { return; } strcpy(m_pszName, pszName); m_cbName = strlen(pszName);}
![Page 47: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/47.jpg)
47
Spot the defect
Class foo {
private:
CHAR* m_pszName;
DWORD m_cbName;
public:
foo(CHAR* pszName);
CHAR* GetName()
{return m_pszName;}
…
};
foo::foo(CHAR* pszName){ m_pszName = (BYTE*) malloc(NAME_LEN); if (m_pszName == NULL) { return; } strcpy(m_pszName, pszName); m_cbName = strlen(pszName);}
If malloc() fails, this code will crash:foo* pfoo = new foo(“MyName”);if (pfoo) { CHAR c = *(pfoo->GetName());}
![Page 48: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/48.jpg)
48
A better version
Class foo {private: CHAR* m_pszName; DWORD m_cbName;
public: foo(); HRESULT Init(CHAR* pszName);…};
foo::foo(){ m_cbName = 0; m_pszName = NULL;}
HRESULT foo::Init(CHAR* pszName){ HRESULT hr = S_OK; if (pszName) { m_cbName = lstrlen(pszName); m_pszName = (CHAR*)malloc(m_cbName+1); if (m_pszName == NULL) { hr = E_OUTOFMEMORY; return hr; } strcpy(m_pszName, pszName); } else { hr = E_INVALIDARG; } return hr;}
![Page 49: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/49.jpg)
49
6. 熟习剑法刀术 , 所向无敌 - Learn Win32 API Seriously
• Learn Win32 APIs, from MSDN• Why Win32 APIs?
– Well designed– Well tested– Easy to understand– Improve performance dramatically
• Understand the ones you use, read the SDK doc in MSDN
• Pick the best one based on your need
![Page 50: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/50.jpg)
50
Spot the defect
for( i=0; i< 256; i++) {
re[i] = 0;
im[i] = 0;
}
for( k = 0; k < 128; k++)
AvrSpec[k] = 0;
… …
#define FrameLen 200
for(k=0; k<5*40*FrameLen; k++)
lsp[k] = lsp[k + 40*FrameLen];
… …
for(k = 0; k < FrameLen; k++) {
audio[k] = vect[k];
}
… …
![Page 51: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/51.jpg)
51
Better version
for( i=0; i< 256; i++) {
re[i] = 0;
im[i] = 0;
}
for( k = 0; k < 128; k++)
AvrSpec[k] = 0;
… …
#define FrameLen 200
for(k=0; k<5*40*FrameLen; k++)
lsp[k] = lsp[k + 40*FrameLen];
… …
for(k = 0; k < FrameLen; k++) {
audio[k] = vect[k];
}
… …
ZeroMemory(re, 256);
ZeroMemory(im, 256);
ZeroMemory(AvrSpec, 128);
… …
#define FrameLen 200
MoveMemory(lsp, &(lsp[40*FrameLen]), 5*40*FrameLen);
… …
CopyMemory(audio, vect, FrameLen);
… …
![Page 52: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/52.jpg)
52
Spot the defect
TCHAR WindowsDir[MAX_PATH];TCHAR WindowsDir[MAX_PATH];
TCHAR DriveLetter;TCHAR DriveLetter;
GetWindowsDirectory(WindowsDir, MAX_PATH);GetWindowsDirectory(WindowsDir, MAX_PATH);
DriveLetter = WindowsDir[0];DriveLetter = WindowsDir[0];
......
![Page 53: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/53.jpg)
53
Spot the defect
TCHAR WindowsDir[MAX_PATH];TCHAR WindowsDir[MAX_PATH];
TCHAR DriveLetter;TCHAR DriveLetter;
GetWindowsDirectoryGetWindowsDirectory(WindowsDir, MAX_PATH);(WindowsDir, MAX_PATH);
DriveLetter = DriveLetter = WindowsDir[0]WindowsDir[0];;
......
Missing return value check …Missing return value check …
Operating on a random drive if Operating on a random drive if GetWindowsDirectory() failsGetWindowsDirectory() fails
![Page 54: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/54.jpg)
54
Can GetWindowsDirectory fail?
• MSDN has always said “yes”
• Implementation has always said “no”…• …Until Terminal Server!
– Computing GetWindowsDirectory may allocate memory
– If allocation fails, the call returns FALSE
• Result: potential catastrophic errors on Terminal Server
![Page 55: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/55.jpg)
55
A better version
TCHAR WindowsDir[MAX_PATH];TCHAR WindowsDir[MAX_PATH];
TCHAR DriveLetter;TCHAR DriveLetter;
if (!if (!GetWindowsDirectory(WindowsDir, GetWindowsDirectory(WindowsDir,
MAX_PATH)) MAX_PATH)) {{
return E_OUTOFMEMORY; // proper recoveryreturn E_OUTOFMEMORY; // proper recovery
}}
DriveLetter = WindowsDir[0];DriveLetter = WindowsDir[0];
......
![Page 56: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/56.jpg)
56
7. 双手互搏 , 无坚不摧 - Test, but don’t stop there
• Step through in the debugger– Especially the error code paths
• Test as much of your code as you can– If you haven’t tested it, it probably doesn’t work
– If you don’t know how much you’ve tested, it’s less than you expect
• So find out!
• Code review– Have somebody else read it
– And read somebody else’s code!
![Page 57: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/57.jpg)
57
Spot the defect
HRESULT hr = NOERROR;
// Make sure the arguments passed are valid
if (NULL != m_paConnections) {
... // do the right thing
}
else hr = S_FALSE;
if (SUCCEEDED(hr)) {
if (NULL != m_paConnections[0].pUnk) . . .
![Page 58: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/58.jpg)
58
Spot the defect
HRESULT hr = NOERROR;
// Make sure the arguments passed are valid
if (NULL != m_paConnections) {
... // do the right thing
}
else hr = S_FALSE;
if (SUCCEEDED(hr)) {
if (NULL != m_paConnections[0].pUnk) . . .
• SUCCEEDED(S_FALSE) == TRUE• Crash if m_paConnections == NULL
– Easily simulatable in the debugger
![Page 59: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/59.jpg)
59
Better version
HRESULT hr = NOERROR;
// Make sure the arguments passed are valid
if (NULL != m_paConnections) {
... // do the right thing
}
else hr = E_INVALIDARG;
if (SUCCEEDED(hr)) {
if (NULL != m_paConnections[0].pUnk) . . .
![Page 60: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/60.jpg)
60
Spot the defect
//
// Get file size first
//
DWORD dwFileSize = GetFileSize( hFile, NULL );
if ( dwFileSize = -1 ) {
// what can we do ? keep silent
ErrorTrace(0, "GetFileSize failed with %d", GetLastError());
return;
}
Note: GetFileSize returns –1 if it fails.
![Page 61: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/61.jpg)
61
Spot the defect
//
// Get file size first
//
DWORD dwFileSize = GetFileSize( hFile, NULL );
if ( dwFileSize = -1 ) {
// what can we do ? keep silent
ErrorTrace(0, "GetFileSize failed with %d", GetLastError());
return;
}
Note: GetFileSize returns –1 if it fails.
Always return as errors occur without Always return as errors occur without proceedingproceeding
![Page 62: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/62.jpg)
62
Better version
//
// Get file size first
//
DWORD dwFileSize = GetFileSize( hFile, NULL );
if ( -1 == dwFileSize ) {
// what can we do ? keep silent
ErrorTrace(0, "GetFileSize failed with %d", GetLastError());
return;
}
Note: GetFileSize returns –1 if it fails.
Compiler will catch the error if you miss “=“Compiler will catch the error if you miss “=“
![Page 63: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/63.jpg)
63
8. 活用段言 - Use, don’t abuse, Assertions
• Use Assertions because– Useful for documentation
• Describe assumptions• Describe “impossible” situations
– Useful for debugging• Help diagnose problems• May detect problems earlier
• Don’t abuse Assertions because– Assertions are usually no-ops in a free/release build
• Don’t use Assertions in situations that can occur in practice
![Page 64: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/64.jpg)
64
Spot the defect
CHAR * pch;
pch = GlobalAlloc(10);
ASSERT(pch != NULL);
pch[0] = 0;
![Page 65: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/65.jpg)
65
Spot the defect
CHAR * pch;
pch = GlobalAlloc(10);
ASSERT(pch != NULL);
pch[0] = 0;
• ASSERT is (usually) a no-op in a free build– And asserts should not be used for things that will
happen in practice
Program crash when out of memory
![Page 66: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/66.jpg)
66
A better version!
CHAR * pch;
pch = GlobalAlloc(10);
If (NULL == pch) {
return E_OUTOFMEMORY;
}
pch[0] = 0;
![Page 67: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/67.jpg)
67
9. 草木皆兵 , 不可大意 - Avoid Assumptions
• Don’t assume good behavior– There will be badly-written apps
• Don’t assume you can trust data– Validate data you can’t trust
• Public interfaces• User input• File contents
– Test your validation code!
• Don’t assume you know all your users– An interface may have unexpected clients– … and not all of them are friendly
• Document the assumptions you make, use ASSERT
![Page 68: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/68.jpg)
68
Spot the defect
CIRRealExtractor::CIRRealExtractor( HRESULT* hr,
const BITMAPINFOHEADER *lpbmi, const void *lpvBits, const RECT *prectBlock)
{
… …
*hr = ContainDIB(lpbmi, lpvBits, prectBlock);
};
![Page 69: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/69.jpg)
69
Spot the defect
CIRRealExtractor::CIRRealExtractor( HRESULT* hr,
const BITMAPINFOHEADER *lpbmi, const void *lpvBits, const RECT *prectBlock)
{
… …
*hr = ContainDIB(lpbmi, lpvBits, prectBlock);
};
• Crash if “hr” is passed in as NULL!– Crash in a C++ constructor is the last thing
you want to do…
![Page 70: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/70.jpg)
70
A better version
CIRRealExtractor::CIRRealExtractor( HRESULT* hr,
const BITMAPINFOHEADER *lpbmi, const void *lpvBits, const RECT *prectBlock)
{
… …
if (hr) {
*hr = ContainDIB(lpbmi, lpvBits, prectBlock);
}
};
![Page 71: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/71.jpg)
71
But wait, a even better version…
CIRRealExtractor::CIRRealExtractor()… …HRESULT CIRRealExtractor::Init( const BITMAPINFOHEADER *lpbmi, const void *lpvBits,
const RECT *prectBlock){… … // lpbmi, lpvBits, and prectBlock can never be NULL ASSERT( lpbmi != NULL); ASSERT( lpvBits != NULL); ASSERT( prectBlock != NULL);
return ContainDIB(lpbmi, lpvBits, prectBlock);};
![Page 72: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/72.jpg)
72
Spot the defect
• Random reboots in low memory situations– Immediate cause: services.exe exits.– Why would services.exe exit?
• Would you believe …– … that services often call wscicmp (and other
string functions)?– … that calling these functions can cause your
program to exit?
![Page 73: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/73.jpg)
73
Code inside wscicmp()
… …
if ( _locktable[locknum] == NULL ) {
if ( (pcs =
_malloc_crt(sizeof(CRITICAL_SECTION)))
== NULL )
_amsg_exit(_RT_LOCK);
… …
![Page 74: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/74.jpg)
74
The defect
… …
if ( _locktable[locknum] == NULL ) {
if ( (pcs =
_malloc_crt(sizeof(CRITICAL_SECTION)))
== NULL )
_amsg_exit(_RT_LOCK);
… …
• Wscicmp assumed the lock allocated successfully, or it’s ok to exit!
• Good or bad, I am the one with the bug!
![Page 75: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/75.jpg)
75
10. 最高境界 , 无招胜有招 - Stop writing so much code
• More code is not better!• Do you really need your own …
– Memory allocator? global operator new?– Assertion macro?– String/Handle/Smart Pointer class?– Hash table?– …
• Think twice before you cut-and-paste– Copied code is copied bugs
![Page 76: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/76.jpg)
76
Some highlights…
• In the Win2K code base:– Over 100 different global operator news– Over 80 different string implementations– Hundreds (thousands?) of copied functions– 9 different JPEG implementations– 3 copies of atlimpl.cpp (3 different versions)– Exactly duplicated ANSI/UNICODE files – …
![Page 77: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/77.jpg)
77
欲练神功 , 端正态度It’s all about attitude
• Take pride in your code– Want it to be perfect
• Correct, reliable, clean, simple, high-performance (speed, memory, …)
– Want it to be a “role model”
• Don’t get your ego wrapped up in it– Admit that your code’s not perfect– Actively seek out problems– Strive to improve it
![Page 78: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/78.jpg)
78
Spot the detect
Comment from PREfix source code:/* In theory it might be possible to create the data
with the right scope, but my attempts to do so have all created crashes of one sort or another. Since we only use this information to improve the clarity of our output, I'm just not creating it in this situation. */
![Page 79: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/79.jpg)
79
Spot the detect
Comment from PREfix source code:/* In theory it might be possible to create the data
with the right scope, but my attempts to do so have all created crashes of one sort or another. Since we only use this information to improve the clarity of our output, I'm just not creating it in this situation. */
i.e., “I know the right thing to do but I couldn’t make it work so I gave up.”
![Page 80: 10 Things You Can Do To Write Better Code 写好代码的十个秘诀](https://reader035.vdocuments.site/reader035/viewer/2022081417/56814c48550346895db94e15/html5/thumbnails/80.jpg)
80
Happy Coding