📄 chapter6.html
字号:
The template for a LOCAL function is almost identical to an APIENTRY function. <br><br><table bgcolor="#CCCCEE" cellpadding=0 cellspacing=0><tr><td><pre><b>Template for a LOCAL function</b>return-type LOCAL FunctionName( type arg1, ..., type argN ){ (function body, usually in fault-tolerant form)} /* FunctionName */</pre></tr></td></table> <br>The comment header and body style are the same except that APIENTRY has been replaced by LOCAL. <br><br>Because LOCAL functions are intended to be private functions, callable only by the module they are contained in, you should try to ensure that they can be called only by the one module. Another potential problem is how to name the LOCAL functions. You do not want to have to worry about name conflicts with LOCAL functions in other modules. <br><br>Luckily, C provides a solution to these problems. <br><br>If a function is declared as static, it is guaranteed by C that the function is visible only to the source file that declared the static function. What this means is that the function cannot be called from other source files because the function is not even visible to them. You no longer have to worry about name conflicts of LOCAL functions between modules because the LOCAL function names are not even visible to the other modules. <br><br><table bgcolor="#CCCCEE" cellpadding=0 cellspacing=0><tr><td><pre><b>The LOCAL and LOCALASM define</b>#define LOCAL static NEAR FASTCALL#define LOCALASM static NEAR PASCAL</pre></tr></td></table> <br>If you are programming in a 32-bit flat model environment, LOCAL is defined to be static because NEAR, FASTCALL and PASCAL are all defined to be nothing (see <a href="chapter3.html#segmentedflat">§3.2.1</a>). However, if you are using Microsoft C8, several optimizations can be applied to LOCAL functions. <br><br>The first optimization is the usage of NEAR. This tells the compiler that the function is in the same code segment as the caller of the function and that a near (16-bit) function call should be used instead of a far (32-bit) function call. There is a big performance hit when you compare the execution speed of a far call to that of a near call. A far function call can be up to five times as slow as a near function in using Intel 80486 protected-mode. <br><br>The second optimization is the usage of FASTCALL. This instructs the compiler to attempt to pass as many arguments as possible to the function through the CPU's registers instead of on the stack. <br><br>The LOCALASM define is used for local functions containing assembly code. This is needed for Microsoft C8 because assembly code and the register calling convention are incompatible. Using PASCAL provides a savings in code size due to how arguments are pushed and popped (see <a href="chapter2.html#pascalcalling">§2.1.11</a>).<br><a name="sample"><br></a><table bgcolor="#F0F0F0"><tr><td><img src="images/windows.gif"> <big><b>6.7 A Sample Module</b></big> <br><br>What follows is a simple code wrapper around the standard C run-time library open(), read(), write() and close() calls. <br><br><img src="images/windows.gif"> <b>6.7.1 The Include File</b><br><br><table bgcolor="#CCCCEE" cellpadding=0 cellspacing=0><tr><td><pre><b>HDOSFH include file section</b>NEWHANDLE(HDOSFH);...#ifdef USE_LOWIO/*-------------------------------------------------------------- * * Access to low-level I/O run-time library functions * *-------------------------------------------------------------*/#include <fcntl.h>#include <sys\types.h>#include <sys\stat.h>#include <io.h>#endif#ifdef USE_HDOSFH/*-------------------------------------------------------------- * * Code wrapper to low-level file I/O * *-------------------------------------------------------------*/EXTERNC HDOSFH APIENTRY DosOpenFile ( LPSTR );EXTERNC WORD APIENTRY DosRead ( HDOSFH, LPVOID, WORD );EXTERNC WORD APIENTRY DosWrite ( HDOSFH, LPVOID, WORD );EXTERNC HDOSFH APIENTRY DosCloseFile ( HDOSFH );#endif</pre></tr></td></table> <br><img src="images/windows.gif"> <b>6.7.2 The Module File</b> <br><br><table bgcolor="#CCCCEE" cellpadding=0 cellspacing=0><tr><td><pre><b>HDOSFH module</b>/****************************************************************//* *//* (project name) *//* *//* Copyright (date) (Company Name). All rights reserved. *//* *//* This program contains the confidential trade secret *//* information of (Company Name). Use, disclosure, or *//* copying without written consent is strictly prohibited. *//* *//****************************************************************//*pm-------------------------------------------------------------- * * OUTLINE: * * This module provides access to the low-level file I/O * functions of the standard Microsoft C run-time library. * * IMPLEMENTATION: * * This module is simply a code wrapper module. * * NOTES: * *--------------------------------------------------------------*/#define USE_LOWIO#define USE_HDOSFH#include "app.h"USEWINASSERT/*--- The class object ---*/CLASS(hDosFh, HDOSFH) { int fh; };/*pf-------------------------------------------------------------- * * DESCRIPTION: (Open File) JLJ * * Attempt to open a file * * ARGUMENTS: * * lpFilename - The name of the file to open * * RETURNS: * * A file object handle or NULL if there was some error * in opening the specified file. * *--------------------------------------------------------------*/HDOSFH APIENTRY DosOpenFile( LPSTR lpFilename ){ HDOSFH hDosFh=NULL; int fh=open(lpFilename, _O_RDWR|_O_BINARY); if (fh!=-1) { NEWOBJ(hDosFh); hDosFh->fh = fh; } return (hDosFh);} /* DosOpenFile *//*pf-------------------------------------------------------------- * * DESCRIPTION: (Close File) JLJ * * Close a previously opened file * * ARGUMENTS: * * hDosFh - The file object or NULL * * RETURNS: * * NULL * *--------------------------------------------------------------*/HDOSFH APIENTRY DosCloseFile( HDOSFH hDosFh ){ VERIFYZ(hDosFh) { int nResult=close(hDosFh->fh); WinAssert(!nResult); FREE(hDosFh); } return (NULL);} /* DosCloseFile *//*pf-------------------------------------------------------------- * * DESCRIPTION: (Read File) JLJ * * Attempt to read a block of information from a file. * * ARGUMENTS: * * hDosFh - The file object * lpMem - Pointer to memory buffer * wCount - Number of bytes to read into the memory buffer * * RETURNS: * * The number of bytes that were actually read * *--------------------------------------------------------------*/WORD APIENTRY DosRead( HDOSFH hDosFh, LPVOID lpMem, WORD wCount ){ WORD wNumRead=0; VERIFY(hDosFh) { wNumRead = (WORD)read(hDosFh->fh, lpMem, wCount); } return (wNumRead);} /* DosRead *//*pf-------------------------------------------------------------- * * DESCRIPTION: (Write File) JLJ * * Attempt to write a block of information to a file. * * ARGUMENTS: * * hDosFh - The file object * lpMem - Pointer to memory buffer * wCount - Number of bytes to write to the file * * RETURNS: * * The number of bytes that were actually written * *--------------------------------------------------------------*/WORD APIENTRY DosWrite( HDOSFH hDosFh, LPVOID lpMem, WORD wCount ){ WORD wNumWritten=0; VERIFY(hDosFh) { wNumWritten = (WORD)write(hDosFh->fh, lpMem, wCount); } return (wNumWritten);} /* DosWrite */</pre></tr></td></table> <br><img src="images/windows.gif"> <b>6.7.3 Commentary</b> <br><br>Use this module as a template on how to write modules. It is bare-bones and targeted to MS-DOS using Microsoft C8, but you should be able to adapt it easily to other environments. I would like to emphasize some parts of this module. <br><br>Completeness. This module is not complete. There are other low-level I/O functions that should be implemented. <br><br>The includes. This module is intended to be a code wrapper that totally replaces the run-time library low-level I/O. Therefore, this module should be the only module that needs to do a #define USE_LOWIO. Notice that the #includes for USE_LOWIO are not done in the source file but are instead done in the global include file. <br><br>Accessing low-level I/O. Whenever any source file wants to access the low-level I/O, it should now use the code wrapper code and do a #define USE_HDOSFH. <br><br>DosCloseFile uses VERIFYZ. It is important that only method functions that destroy an object allow NULL to be passed in as an argument. You do not want to trigger a run-time object verification failure. VERIFYZ performs this task. <br><br>Fault-tolerant methods. Whenever possible, the fault-tolerant form of VERIFY should be used. For functions returning a value, a reasonable failure return value is in place before the run-time verification takes place. This way, even if a bad object handle is unknowingly passed in, the calling code will react to the failure value.</td></tr></table><br><a name="summary"><br></a><big><b>6.8 Chapter Summary</b></big> <br><br> <ul type="disc"><li>The key to successfully coding a hierarchy of modules is that you must always code what to do, not how to do it.<li>In this way, you avoid spreading knowledge about how to do something and instead put this knowledge in a function in one place. You are now free to call the function as many times as you want in as many places as you want. Changing the implementation down the road is a lot easier since the implementation is now isolated in one function.<li>An important benefit of this technique is that it allows for the rapid prototyping of changes to an implementation, because changing the implementation changes only one source file as opposed to many.</ul><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 + -