📄 chapter7.html
字号:
segment/offset pointer. These near and far attributes are only defaults. Mixed-model programming allows the near/far attributes to be specified on a pointer-by-pointer basis. <br><br>My advice to you is to use the large memory model, unless you are ultra concerned with speed. The industry is moving away from segmented architectures toward flat memory model programming, where there are no segments. <blockquote><table bgcolor="#E0E0E0" border=1 cellpadding=2 cellspacing=0><tr><td> Use the large memory model. This will aid porting to flat memory model architectures. </tr></td></table></blockquote>By using the large memory model now, you ease the eventual porting of your software to the flat memory model.</td></tr></table><br><a name="automatedtesting"><br></a><big><b>7.24 Automated Testing Procedures</b></big> <br><br>An automated testing procedure is a function that is designed to automatically test your code for you -- code that you think is already bug-free. A key part of most testing procedures is their use of random number generator class objects. <br><br>Let's suppose that you have just implemented a B-Tree disk-based storage heap for fast access to your database. How are you going to really test it? You could code examples that use the B-Tree class in order to test edge conditions. This is a good idea anyway, but what do you code next? <br><br>A solution that I have found useful and highly effective is to use a random number generator to create data sets that are then thrown at the module to be tested. A random number generator is useful because if a problem is discovered, it can be absolutely recreated by using the same random number seed. <blockquote><table bgcolor="#E0E0E0" border=1 cellpadding=2 cellspacing=0><tr><td> A random number generator is an important part of an automated testing procedure. </tr></td></table></blockquote>In the case of the B-Tree code, you could randomly decide to add or delete a record from the tree and you could randomly vary the size of the records being added. You could also decide to randomly restart the test. As you add records into the database and read them back, how do you verify the integrity of the randomly sized record? One slick technique is to use another random number generator to fill in the record with random values. The slick part is that all you need to save around in memory to validate the record when it is read back in is the random number seed that was used to generate the random record, not the entire record itself. <br><br>Another big advantage of using random number generators is that given enough time, they can test virtually all cases and code paths. It is a lot like throwing darts. If you keep on throwing a dart at the dart board, the center target is eventually hit. It is only a matter of time. The question is not if the target is hit, but when. <br><br>What you are doing with the automated testing procedure is taking a module that is considered to be bug-free and subjecting it to a torture test of random events over time. Assuming there is a bug in the module, the automated testing procedure will find it eventually. <blockquote><table bgcolor="#E0E0E0" border=1 cellpadding=2 cellspacing=0><tr><td> If there is a bug in a module, an automated testing procedure will eventually find it. </tr></td></table></blockquote>It is important that the automated testing procedure be written so that it is capable of generating all types of conditions and not just the normal set of conditions. You want to make sure that all the code in the module gets tested. <br><br><table bgcolor="#F0F0F0"><tr><td><img src="images/windows.gif">Do automated testing procedures actually work? Yes! They are what turned up the MS-DOS lost cluster bug and the Windows task-switching bug described in <a href="chapter3.html#systembugs">§3.1</a>. I was putting my own code through a rigorous automated testing procedure and every once in a while the underlying kernel would fail. I guess the use of probability theory pays off.</td></tr></table><br><a name="doctools"><br></a><big><b>7.25 Documentation Tools</b></big> <br><br>Programmers hate to write documentation, but they love to write code and most programmers are willing to comment their code to some degree. An even bigger problem is that even if documentation does exist, it is more than likely out of date because it hasn't been maintained to reflect code changes. <br><br>My solution to this problem is to accept the fact that external documentation is not going to be produced directly. Instead, I am going to produce it indirectly. <br><br>By having all programmers follow a common documentation style in the entire project, it is possible to write a program that scans all source files and produces documentation. <br><br>I use markers in comment blocks to assist me in parsing my comments. For example, module comment blocks begin with /*pm, APIENTRY function comment blocks begin with /*pf and LOCAL function comment blocks begin with /*p. <br><br>In practice, this works great. The AUTODOC program that I use scans all sources files and produces a Microsoft Quick Help file as output. The Brief editor that I use supports Quick Help. I now have instant access to all APIENTRY function documentation at the touch of a key.<br><a name="sourcecontrol"><br></a><big><b>7.26 Source-Code Control Systems</b></big> <br><br>If you are not already using a source-code control system, I would highly recommend that you get one. I like them because they give me access to the source as it existed all the way back to day one. It is also essential for tracking down problems in released software. You may end up with two or three different versions of your software that are all in active use. The source-code control system gives you easy access to the source of any particular version of your software. <br><br>Most source-code control systems follow a get and put methodology. Getting a source file gives the "getter" editing privileges to the source. When changes are complete, the source is put back. <br><br>Before I put back any source, I produce a difference file and review all the changes that I have made to the source. On more than one occasion this has saved me from including a silly programming bug. <blockquote><table bgcolor="#E0E0E0" border=1 cellpadding=2 cellspacing=0><tr><td> Always review changes before checking source code back in. </tr></td></table></blockquote><b>7.26.1 Revision Histories</b> <br><br>An important part of maintaining software is keeping an accurate log of what changes were made to a module and why. Rather than keeping this information in the source file itself, I prefer to use the source-code control system. <br><br>In the source-code control system that I use, a put will prompt me to enter a description of the changes that I have made to the source file. <br><br>The entire revision history is available at any time and is maintained by the source-code control system. In modules that get changed a lot, this technique keeps around the full revision history without cluttering up the source file.<br><a name="monoscreen"><br></a><table bgcolor="#F0F0F0"><tr><td><img src="images/windows.gif"> <big><b>7.27 Monochrome Screen</b></big> <br><br><img src="images/windows.gif"> <b>7.27.1 The Windows Developer</b> <br><br>A monochrome monitor is a must for the Windows-based developer. You can configure the debugging kernel to send debug messages to either a serial communications port or the monochrome monitor. This is configured in the DBWIN.EXE program, which is provided with Microsoft C8. A monochrome monitor is preferred because it is a lot faster when you get a lot of debug messages at once. <br><br>In addition to the system generating debug messages, the programmer can generate them as well by calling OutputDebugString(). The prototype for it is as follows. <br><br><table bgcolor="#CCCCEE" cellpadding=0 cellspacing=0><tr><td><pre><b>OutputDebugString() prototype in windows.h (v3.1)</b>void WINAPI OutputDebugString(LPCSTR);</pre></tr></td></table> <br>OutputDebugString() should not be called in the final release of your software. You do not want messages going to your customer's communication port. In my code, I control this by calling OutputDebugString() only if I detect that the debugging kernel is running. To detect if you are running under debug Windows, use the GetSystemMetrics(SM_DEBUG) call. It returns zero under retail Windows and a non-zero value under debug Windows. <br><br>Another benefit of using a monochrome screen is that most Windows debugging tools have an option to run on the monochrome screen. This way you can see the debug screen and your main screen at the same time. <br><br><img src="images/windows.gif"> <b>7.27.2 The MS-DOS Developer</b> <br><br>Just as in Windows, most MS-DOS debugging tools have an option to run on the monochrome screen. What do you do if you want to send messages to the monochrome screen? <br><br>An OutputDebugString() that can be used by MS-DOS programmers is as follows. <br><br><table bgcolor="#CCCCEE" cellpadding=0 cellspacing=0><tr><td><pre><b>OutputDebugString() for MS-DOS programmers</b>void APIENTRY OutputDebugString( LPSTR lpS ){ LPSTR lpScreen=(LPSTR)0xB0000000; /* base of mono screen */ int nPos=0; /* for walking lpS string */ /*--- Scroll monochrome screen up one line ---*/ _fmemcpy( lpScreen, lpScreen+2*80, 2*80*24 ); /*--- Place new line down in 25'th line ---*/ for (int loop=0; loop<80; ++loop) { lpScreen[2*(80*24+loop)] = (lpS[nPos]?lpS[nPos++]:' '); }} /* OutputDebugString */</pre></tr></td></table> <br>The monochrome screen is memory mapped and is located at segment 0xB000. Every character on a monochrome screen is actually composed of 2 display bytes. One byte is the character to display and the other byte contains attribute information such as blinking, inverted, and so on. <br><br>This code works by first scrolling the monochrome screen by performing a memory copy. Next, the string is placed into line 25 of the monochrome screen. The string is placed space padded at the end to make sure that the previous contents of the twenty-fifth line are overwritten.</td></tr></table><br><a name="debugtiming"><br></a><table bgcolor="#F0F0F0"><tr><td><img src="images/windows.gif"> <big><b>7.28 Techniques for Debugging Timing Sensitive Code</b></big> <br><br>Application code should never have any timing dependencies. However, system level or interrupt code will more than likely have timing constraints. An example is an interrupt handler for a synchronous communications protocol. These drivers can be especially hard to debug because there is always communications traffic on the line and the protocol itself is timing sensitive. Using OutputDebugString() to help you debug the code wastes too much time and affects the timing sensitive code you want to debug, so an alternative is needed. <br><br><img src="images/windows.gif"> <b>7.28.1 PutMonoChar() Function for MS-DOS</b> <br><br>One technique that I have used successfully to debug timing sensitive code is to write a few informative characters directly into the monochrome screen video memory, in effect displaying a message on the monochrome monitor. For example, PutMonoChar() places a character at a specific row and column on the monochrome screen. <br><br><table bgcolor="#CCCCEE" cellpadding=0 cellspacing=0><tr><td><pre><b>PutMonoChar(), for MS-DOS</b>void APIENTRY PutMonoChar( int nRow, int nCol, char c ){ if ((nRow>=0) && (nRow<25) && (nCol>=0) && (nCol<80)) { *(LPSTR)(0xB0000000+2*(nRow*80+nCol)) = c; }} /* PutMonoChar */</pre></tr></td></table> <br>PutMonoChar() works by first validating that the input nRow and nCol are valid. It then writes the character directly into monochrome screen video memory. <br><br>The advantage of using PutMonoChar() as opposed to OutputDebugString() for debug messages is that it is so much faster and is unlikely to adversely affect the timing sensitive code you want to debug. This is because PutMonoChar() is just placing one character down instead of OutputDebugString(), which is placing an entire line down and scrolling the entire monochrome screen.</td></tr></table><br><br><hr><center><small>Copyright © 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 + -