⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chapter3.html

📁 Writing Bug-Free C Code
💻 HTML
📖 第 1 页 / 共 3 页
字号:
 recommend that you remove assertion statements, you still want to play it safe.  You do not want to end up accidentally removing code that is needed to make your program run correctly.<br><a name="naming"><br></a><big><b>3.4 Naming Conventions</b></big> <br><br>One of the most important aspects of programming is the use of a consistent naming convention.  Without one, your program ends up being just a jumble of various techniques and hence hard to understand.  With a naming convention, your program is more readable and easier to understand and maintain. <br><br>I will describe the naming conventions that I have used to code a large application that have worked quite well for me. <br><br><a name="namingmacros"></a><b>3.4.1 Naming Macros</b> <br><br>Macro names should always be in uppercase and may contain optional underscore characters.  For macros that take arguments, I prefer not to use the underscore character anywhere (e.g., NUMSTATICELS()).  For macros that define constant numeric values, underscore characters are OK (e.g., MAX_BUFFER_SIZE).   <blockquote><table bgcolor="#E0E0E0" border=1 cellpadding=2 cellspacing=0><tr><td>   Macro names should be in uppercase.   </tr></td></table></blockquote>Macro names in uppercase stand out and draw attention to where they are located.  Some macros that are universally used throughout almost all code are allowed to be in mixed upper- and lowercase.  An example of a macro like this is the <a href="chapter3.html#winassert">WinAssert() macro &sect;3.3</a>. <br><br>There are many times that a set of macros contain a common subexpression.  When this happens, I create another macro that contains the common sub-expression.  The sole purpose of this type of macro is that it is to be used by other macros and not in the source code.  A naming convention I use to help me remember that the macro is private to other macros is to name it with a leading underscore character.   <blockquote><table bgcolor="#E0E0E0" border=1 cellpadding=2 cellspacing=0><tr><td>   Macros beginning with an underscore are to be used only in other   macros, not explicitly in source code.   </tr></td></table></blockquote><b>3.4.2 Naming Data Types</b> <br><br>I can remember the difficulty I had coming up with good data type names when I first started to code.  I was using mixed upper- and lowercase for data type names and variable names.  However, it became harder and harder to read the program.  I always ended up wanting the variable name to be spelled the same as the data type name but could not do this, so I ended up calling it something different which made the program hard to understand. <br><br>The convention that I finally settled upon is that all data types should be in uppercase.  The variable names can then be spelled the same, but in mixed upper- and lowercase.  This convention may at first seem awkward, but in practice I have found that it works well.   <blockquote><table bgcolor="#E0E0E0" border=1 cellpadding=2 cellspacing=0><tr><td>   New data types should be in uppercase.   </tr></td></table></blockquote>Data type names should also avoid using the underscore character.  This is because macro names may use the underscore character and it is best to avoid any possible confusion or ambiguity over whether or not an uppercase name is a data type name or macro name. <br><br><b>3.4.3 Declaring Data Types</b> <br><br>New data types must be declared with a typedef statement.  While it is possible to use a macro to create what looks like a new data type, it is not a true data type and is subject to subtle coding problems.   <blockquote><table bgcolor="#E0E0E0" border=1 cellpadding=2 cellspacing=0><tr><td>   New data types must be declared with a typedef statement, not a macro   definition.   </tr></td></table></blockquote>Consider the data type PSTR, shown below, which is a character pointer. <br><br><table bgcolor="#CCCCEE" cellpadding=0 cellspacing=0><tr><td><pre><b>Using typedef to create a new data type</b>typedef char*PSTR;<br><b>Using macros to create a new data type, a bad practice</b>#define PSTR char*<br><b>Using the new PSTR data type</b>PSTR pA, pB;</pre></tr></td></table> <br>In the above example, what is the type of pA and what is the type of pB?  In the case of using typedef to create the new data type, the type of pA and pB is a character pointer, which is as expected.  However, in the case of using the macro to create the new data type, the type of pA is a character pointer and the type of pB is a character.  This is because PSTR pA, pB really represents char *pA, pB which is not the same as char *pA, *pB. <br><br>This example shows the danger in using macros to declare new data types in the system.  Therefore, you should avoid using macros to declare new data types. <br><br><b>3.4.4 Naming Variables</b> <br><br>All variables should be named using the Hungarian variable naming convention with mixed upper- and lowercase text and no underscore characters.   <blockquote><table bgcolor="#E0E0E0" border=1 cellpadding=2 cellspacing=0><tr><td>   Variables should be named using Hungarian notation.   </tr></td></table></blockquote>The Hungarian naming convention states that you should prefix all variable names with a short lowercase abbreviation for the data type of the variable name.  (See Table 3-1). <br><br><ul><table border=1 cellspacing=0><tr><td><b>Prefix</b></td><td><b>Data Type</b></td></tr><tr><td>a</td><td>array of given type</td></tr><tr><td>b</td><td>BOOL: true/false value</td></tr><tr><td>by</td><td>BYTE</td></tr><tr><td>c</td><td>char</td></tr><tr><td>dw</td><td>DWORD</td></tr><tr><td>h</td><td>handle or abstract pointer</td></tr><tr><td>l</td><td>long</td></tr><tr><td>lp</td><td>long pointer</td></tr><tr><td>n</td><td>int</td></tr><tr><td>p</td><td>pointer</td></tr><tr><td>w</td><td>WORD</td></tr></table>Table 3-1: Hungarian Notation Prefixes</ul>For example, nSize is an integer, bOk is a BOOL and hIcon is an abstract handle.  Prefixes may be combined to produce a more descriptive prefix.  An example would be lpnCount, which is a long pointer to an integer and lpanCounts, which is a long pointer to an array of integers. <br><br>The advantage of Hungarian notation is that you are much more likely to catch a simple programming problem early in the coding cycle, even before you compile.  An example would be nNewIndex = lIndex+10.  Just by glancing at this you can see that the left-hand side is an integer and the right-hand side is a long integer.  This may or may not be what you intended, but the fact that this can be deduced without seeing the original data declarations is a powerful concept.   <blockquote><table bgcolor="#E0E0E0" border=1 cellpadding=2 cellspacing=0><tr><td>   Hungarian notation allows you to know a variable's data type without   seeing the data declaration.   </tr></td></table></blockquote>The Hungarian notation handles all built-in data types, but what about derived types?  A technique that I have found useful is to select an (uppercase) data type name that has a natural mixed upper- and lowercase name.<br><br><table bgcolor="#F0F0F0"><tr><td><img src="images/windows.gif">An example from the Windows system is the HICON data type and the hIcon variable name.  As another example, let's consider a queue entry data type called LPQUEUEENTRY.  A variable name for this could be lpQueueEntry. </td></tr></table> <br>This convention works great for short data type names like HICON, but not so well for long data type names like LPQUEUEENTRY.  The resulting variable name lpQueueEntry is just too long to be convenient.  In this case, an abbreviation like lpQE should be used.  However, make sure that lpQE is not also an abbreviation for another data type in your system. <br><br>Whatever technique you use to derive variable names from data type names is fine provided that there is only one derivation technique used in your entire program.  A bad practice would be to use lpQE in one section of code and lpQEntry in another section of code.   <blockquote><table bgcolor="#E0E0E0" border=1 cellpadding=2 cellspacing=0><tr><td>   A data type must have a single and unique variable derivation.   </tr></td></table></blockquote><b>3.4.5 Naming Functions</b> <br><br>Functions should be named using the module/verb/noun convention in mixed upper- and lowercase text with no underscore characters.   <blockquote><table bgcolor="#E0E0E0" border=1 cellpadding=2 cellspacing=0><tr><td>   Functions should be named using the module/verb/noun convention.   </tr></td></table></blockquote>Suppose you have just started a project from scratch.  There is only one source file and the number of functions in it is limited.  You are naming functions whatever you feel like and coding is progressing rapidly.  Two months go by and you are working on a new function that needs to call a specialized memory copy routine you wrote last month.  You start to type in the function name, but then you hesitate.  Did you call the function CopyMem() or MemCopy()?  You do not remember, so you look it up real quick. <br><br>This actually happened to me and the solution was simple.  Follow the Microsoft Windows example of naming functions using the verb/noun or action/object technique.  So, the function should have been called CopyMem(). <br><br>This solved my immediate problem, but not the long-term problem.  It wasn't long before I had thousands of function names, some with similar sounding verb/noun names.  My solution was to prefix the verb/noun with the module name. <br><br>Suppose you have a module that interfaces with the disk operation system of your environment.  An appropriate module name would be Dos and several possible function names are DosOpenFile(), DosRead(), DosWrite() and  DosCloseFile(). <br><br>Module names should contain two to five characters, but an optimum length for the module name is three to four characters.  You can almost always come up with a meaningful abbreviation for a module that fits in three to four characters.<br><a name="summary"><br></a><big><b>3.5 Chapter Summary</b></big> <br><br> <ul type="disc"><li>A rock-solid layer needs to be built upon all system level interfaces because system level interfaces contain bugs.  You cannot assume that they are bug-free.  I have been burned too many times to trust system level calls blindly.<li>When you do make assumptions in calling system code, it is best to WinAssert() these situations in a code wrapper.  When a function does fail and you assumed that it never would, you want to know about it so that you can fix the problem and reevaluate your assumption.<li>Macros can be used as an abstraction layer to allow your code to be ported without having to change your source files.  Instead, just change the macros contained in your include files and recompile.  The macro name in the source file is specifying what to do.  The macro body in the include file is specifying how to do it.<li>It is a good idea to use WinAssert()'s generously in your code.  The WinAssert() provides run-time checking of design-time assumptions and signals a design flaw when it occurs.  Use the fault-tolerant form of WinAssert() whenever possible.<li>When programming in a large project, it is crucial that a consistent naming convention be used throughout the entire project.  This helps prevent misunderstandings that produce buggy code.<li>Macro names should be in uppercase.  A macro beginning with an underscore character is intended to be used only in other macros, not explicitly in source code.<li>New data types should be in uppercase and declared with a typedef statement, not a macro definition.<li>Variables should be named using the Hungarian notation.  This notation allows you to know the type of a variable without seeing the data declaration.<li>Functions should be named using the module/verb/noun convention.</ul> <br><br><hr><center><small>Copyright &copy; 1993-1995, 2002-2003 Jerry Jongerius<br>This book was previously published by Person Education, Inc.,<br>formerly known as Prentice Hall. ISBN: 0-13-183898-9<br></small></center></html></body>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -