-------------------------------------------------- --- Manual Additions/Modifications --- -------------------------------------------------- PC-lint for C/C++ Version 8.00x This readme.txt supplements the on-line PC-lint manual entitled "Reference Manual for PC-lint/Flexelint" found in the installation directory under the name "pc-lint.pdf" You have permission to print out the reference manual in whole or in part only in support of the authorized use of this software and not for general distribution or resale. ------ Support for Microsoft through Visual Studio 2008 ------ We currently support Microsoft Visual C/C++ 9.0 (as well as all earlier versions of the Microsoft compiler series). Support comes mainly from the compiler options files (co-...lnt). For example options files co-msc70.lnt, co-msc71.lnt, co-msc80.lnt and co-msc90.lnt support versions 7.0, 7.1, 8.0 and 9.0 respectively. ------ Support for Borland Project Files ------ As of patch level 8.00j we support the Borland 6.0 Project Files (.bpr) in a manner similar to the support for Microsoft .dsp and .vcproj files. That is the command: lint-nt a.bpr will generate to standard out options and names of modules that it finds within the project file. The default location of the Borland system is: c:\program files\borland\cbuilder6 This can be modified by presetting macro BCB. Thus lint-nt -d"BCB=c:\\my program files\\borland\\cbuilder6" a.bpr is the appropriate command if the location of CBuilder6 is in the directory specified. ------ A caveat for 8.00p ------ When moving to Patch level 8.00p from the prior patch level (8.00o) you might experience a problem whereby a previously suppressed message is no longer suppressed. This could occur with the use of -esym employed upon an identifier within a class within a namespace. For example: namespace A { class B { int n; }; } will now correctly indicate that A::B::n is not used whereas earlier patch levels indicated that B::n was not used. A use of an option of the form: -esym( xxx, B::n ) will now be ineffective in suppressing the message. The preferred option is to use the full name including namespace as in: -esym( xxx, A::B::n ) If there are a large number of such options and if it would be an unbearable chore to make the above change for each and every one of those options then another possibility exists. You may employ, for example, the following option: -esym( xxx, [*::]B::n ) The brackets specify an optional sequence and is currently undocumented. This suppresses message xxx for B::n and for every B::n embedded in any namespace or nested sequence of namespaces. This technique allows for a search and replace operation to alter a large number of esym options relatively painlessly. ------ Printing the Reference Manual ------ You have permission to print out the Reference Manual (or other related documentation) in whole or in part in support of the use of this software. ------ What's New ------ To find out what we've added to the product since Version 7.50, check out Chapter 18 "What's New" in the Reference Manual. ------ Front End ------ Your linting experience will be considerably enhanced by adapting your favorite editor or compiler environment to the task of sequencing from error to error. See Section 3.5 of the Reference Manual. ------ Multiple Passes ------ By default, PC-lint/FlexeLint will go through all your modules in one pass. For projects not previously linted there will be enough messages to look at. However, with just one pass, you will not be taking full advantage of our new interfunction value tracking. With just one pass, we will not know about dangerous return values for functions that are defined later than they are called, and we will not know about dangerous arguments for functions that are defined early. To introduce a second pass you need only to add the command line option: -passes(2) or, if this syntax presents a problem with your Shell, you may use: -passes[2] or, in some cases, -passes=2 is needed. Of course, you can replace the 2 with any number you wish. The larger the number the more bugs can be found and the more time will be required. See Section 9.2.2, "Interfunction Value Tracking". ------ Additional Options ------ The following options have been added. o Commercial @ is a modifier (+f@m) This is a feature required by some embedded compilers that employ a syntax such as: int @interrupt f() { ... } The @interrupt serves as a modifier for the function f (to indicate that f is an interrupt handler). Normally '@' would not be allowed as a modifier. If the option +f@m is given then '@' can be used in the same contexts as other modifiers. There will be a warning message (430) but this can be suppressed with a -e430. The '@' will otherwise be ignored. The keyword that follows should be identified either as a macro with null value as in -dinterrupt= or as a reserved word using +rw(interrupt). o Parse .net attributes, +fat Dot net (.net) attributes are contained within square brackets. E.g. [propget, id(1)] void f( [out] int *p ); The square brackets and information contained therein is a non standard extension to the C/C++ standards supported by the Microsoft Visual C 7.00 compiler. Remarkably this doesn't appear to interfere (or be ambiguous) with other uses of square brackets within the language. For this reason the flag is normally ON. To turn off such processing use -fat. o Explicit Throw flag (+fet) In early releases of 8.0 (8.0d and earlier) we provided a method of checking exception specifications to prevent exception leaks, etc. Unfortunately we were too aggressive and a number of programmers pointed out that since a function that doesn't declare to throw can throw any exception, then it is at least theoretically possible that by adding an exception specification to a function that doesn't have one, you will induce the dreaded unexpected() call. So we made the appropriate modifications and we began getting the opposite complaint. Some programmers were quite happy with the old system since it allowed them to track and control their own exceptions especially in situations where library functions with undocumented exceptions were non-existent. To resolve the problem and make everyone happy, version 8.00g has a new flag. The Explicit Throw flag (+fet) is normally OFF. If the flag is OFF then the absence of an exception specification (the throw list for a function) is treated as a declaration that the function can throw any exception. This is standard C++. If the flag is ON, however, the function is assumed to throw no exception. In effect, the flag says that any exception thrown must be explicitly declared. Consider double sqrt( double x ) throw( overflow ); double abs( double x ); double f( double x ) { return sqrt( abs(x) ); } In this example, sqrt() has an exception specification that indicates that it throws only one exception (overflow) and no others. The functions abs() and f(), on the other hand, have no exception specification, and are, therefore, assumed to potentially throw all exceptions. With the Explicit Throw flag OFF you will receive no warning. With the flag ON (with a +fet), you will receive Warning 1550 that exception overflow is not on the throw list of function f(). The advantage of turning this flag ON is that the programmer can obtain better control of his exception specifications and can keep them from propagating too far up the call stack. This style of analysis is very similar to that employed quite successfully by Java. The disadvantage, however, is that by adding an exception specification you are saying that the function throws no exception other than those listed. If a library function throws an undeclared exception (such as abs() above) you will get the dreaded unexpected() function call. See Scott Meyers "More Effective C++", Item 14. Can you have the best of both worlds? Through the magic of macros it would appear that you can. Define #define Throws(X) throw X which then is used as: float f( float x ) Throws((overflow,underflow)) { ... Notice the required double set of parentheses which are needed to get an arbitrary list of exceptions into a single macro. When you compile you can define Throws to be null and when you lint you can define Throws as above. This can be done most easily by doing a #ifdef on the _lint preprocessor variable (defined while running our product). o Function takes Custody flag (ffc) This flag is normally ON. It signifies that a function will automatically assume custody of a pointer if the argument is not of the form const T * where T is some type and is not library. Turning this flag OFF (with a -ffc) will mean that a given function will not take custody of a pointer unless explicitly directed to do so via a custodial semantic for that function and argument. See option -sem. See also message 429. o The Inhibit Inference flag (fii) This flag is normally OFF. It had been by default ON in versions of PC-lint/FlexeLint prior to versions 8.00m. The purpose is to suppress inference formation during Specific Walks and during the evaluation of expressions involving nul-terminated strings. These inferences were prone to error and were resulting in undeserved messages. Owing to steady progress in the accuracy of making such inferences the flag has been made default OFF. To obtain the prior behavior (i.e. as it was in version 8.00L) turn the flag on with +fii. o Macro Concatenation Flag (+fmc) If the flag is ON, a token immediately following a macro with parentheses, will, in effect, be pasted on to the end of the last token of the macro replacement. For example, the code #define A() a int A()x; will normally be greeted with an error according the ANSI/ISO standards because this is equivalent to: int a x; However if the Macro Concatenation flag is turned on (using the option +fmc) the two names are in effect pasted together to produce the equivalent of: int ax; Prior to the Ansi standard the only way to perform a concatenation of this kind was through the device described above. Now the approved mechanism is through the ## operator. The option is a means of supporting older programs that are still employing the older technique. o Treat carriage Return as Newline (+frn) If this flag is ON, carriage return characters (0x0D) in the source input not followed by a Newline (0x0a) are treated as Newline characters (i.e., as line breaks). This is necessary to process Macintosh style source code on the PC or Unix or their derivatives. With this flag ON all three conventions (NL alone, CR alone, and CR NL in combination) are taken to be a Newline so that you may mix header files. o -A(C90) The -A option (strict ANSI) has been upgraded to conform to the C99 standard. In particular Elective Note 950 is not issued for // comments in C code. To obtain the older style you can use the option -A(C90) which says that if the module is a C module it should conform strictly to the version of C identified as C90. To get complaints about the use of // you still need to enable 950. o --idirectory This is like -idirectory but places a lower priority on that directory. All directories specified by -i are searched before directories named by --i. This is to support compilers that always search through compiler-provided library header directories after searching user-provided directories. Example: suppose there is a header file named 'bar.h' in both directory '/foo' and directory 'local'. Then: // in std.lnt: --i/foo // search foo with low priority -ilocal // search local with high priority // in t.cpp: #include // finds the version in 'local' o -I- for Sun CC After Lint processes the option -csun, it will behave as Sun CC does when it encounters the -I- option (Refer to the Sun C++ User's Guide for details). After this option is given, quote style headers will not be searched for in the directory of the including file, and angle bracket header files will be searched for only in directories that are mentioned in -i options after the -I-. o -template The existing option -template(bits) has a new bit 100 which has the following meaning. The issue involves instantiating non-dependent template-id's. In the past (pre 8.00r patch level) we did not always instantiate these template-id's during a template definition. Currently we are more aggressive in doing this instantiation (up to the limits required by the language). Not all compilers (or even configurations of a particular compiler) instantiate identically. If you are experiencing problems owing to this change, you may turn on this flag by using the following option: ++template( 100 ) Another new bit is 200, which has the following meaning. The issue involves unqualified name lookup and base classes of dependent type. Consider the following case: template struct A { typedef char B; }; template struct C : public A { int f( const B* ); // ERROR }; Because of the reference to B in the parameter list of C::f, this example is ill-formed according to section 14.6.2, paragraph 3 of the 2003 version of the ISO C++ Standard, which states: "In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member." However, during unqualified name lookup, some popular compilers do search in dependent (and formerly dependent) base classes both at template definition and at template instantiation time. To enable such name lookup behavior in Lint, use ++template(200). This flag will be ON by default when -cmsc or -cbc are given. Note that MSVC7.1 does adhere to the Standard in this regard when given the /Za flag. Therefore, if you compile with /Za, you should probably also add --template(200) after -cmsc in your Lint configuration. Users of more recent versions of the Borland compiler may also choose to disable this -template bit. Note: With the addition of the 200 bit we are now able to retire the undocumented bit 40 which enabled what is now the default (standard- conforming) behavior. Yet another new bit is 400, which has the following meaning. The issue involves the use of template parameters in the scope of an explicit specialization. Consider the following case: template struct A; template<> struct A { T n; }; // ERROR According to section 14.6.1, paragraph 3 of the 2003 ISO C++ Standard, "The scope of a template-parameter extends from its point of declaration until the end of its template." So in this example, "T" is not in scope after the semicolon that terminates the definition of the primary template of A. Furthermore, there is nothing to indicate that it is introduced in the scope of A. However, some compilers (for example, versions 6 and 7 of the Microsoft compiler, as well as some other compilers in a backwards-compatibility mode) behave as if the template parameter T had been re-declared at the onset of A. To enable similar behavior in Lint, use ++template(400). This bit is set automatically when -cmsc is used. o multi-thread support A number of customers have asked for some kind of multi-thread support. In particular they have asked us for a way to designate some data as 'Shared' so that only functions that are also marked 'Shared' can access the data; also, Shared functions can only access Shared data and none other. If it were not for the second criterion you could use the volatile qualifier. It so happens that there are a number of old modifier flags that can be used for this purpose. One such is the keyword 'fortran'. This keyword is normally not active. When it was active compilers would use the modifier as a clue to employ a fortran-like calling sequence for any function so designated. Lint would simply ignore these intended semantics and restrict its usage to ensuring that declarations would be consistent with respect to this modifier. For example, you wouldn't want to pass a pointer that points to a Fortran function to a pointer that points to a non-fortran function. These simple type-qualification semantics can be used as the basis for a new keyword, in this case 'Shared'. For example: //lint -rw_asgn(Shared,fortran) struct X { void f() Shared; void g(); ... }; X Shared a; X b; ... a.f(); // OK a.g(); // Error b.f(); // Error b.g(); // OK Using functions rather than member functions we can obtain the same effect. //lint -rw_asgn(Shared,fortran) struct X { ... }; void f( struct X Shared * ); void g( struct X * ); struct X Shared a; struct X b; ... f( &a ); // OK g( &a ); // Error f( &b ); // Error g( &b ); // OK In addition to 'fortran' there are a number of other old modifiers that could be employed including: 'pascal', '_fastcall', and '_loadds'. Any such modifier that is used in the formation of a type will be embedded within that type when the type is displayed for diagnostic purposes. The name that is used by default will be the original qualification name. This name will be overridden when the -rw_asgn option assigns a modifier to some new name. ------ New or Improved Error Messages ------ 89 Argument or option too long ('String') -- The length of an option (shown in String) exceeds an internal limit. Please try to decompose the option into something smaller. At this writing the limit is 610 characters. 96 Unmatched left brace for String on Location -- The purpose of this message is to report the location of a left curly brace that is unmatched by a right curly brace. Such an unmatched left curly can be far removed from the point at which the unbalance was detected (often the end of the compilation unit). Providing the location of the left curly can be extremely helpful in determining the source of the imbalance. 155 Ignoring { }'ed sequence within an expression, 0 assumed -- Some compilers support what looks like a compound statement as a C/C++ expression. For example to define the absolute value of an integer which guarantees that it will be read only once you may use: #define abs(a) { int b = a; b >= 0 ? b : -b; } The last expression in the list is the result. To syntactically support the construct without running amuck we recognize the sequence and issue this message. If you want to use the facility just suppress the message. 156 Braced initializer for scalar type 'Name' -- An example of an initializer that will draw this complaint is as follows. int s[] = { { 1 } }; After the compiler has seen the first curly it is expecting to see a number (or other numeric expression). Compilers that strictly adhere to the ISO C and C++ Standards will flag this as ill-formed code. Note that it is legal (but somewhat arcane) to employ a left curly at the top-level when initializing an object of scalar type. For example, the following is well-formed: int i = { 0 }; // OK; initialize scalar i with 0. char *t = { "bar" }; // OK; initialize scalar t with a pointer to // a statically allocated array. Also note: as the example above implies, this message can apply to pointers to arrays of char; it does not apply to arrays. 157 No data may follow an incomplete array -- An incomplete array is allowed within a struct of a C99 or C++ program but no data is allowed to appear after this array. For example: struct A { int x; int a[]; int b; }; This diagnostic is issued when the 'b' is seen. 160 The sequence '( {' is non standard and is taken to introduce a GNU statement expression -- Lint encountered the sequence '( {' in a context where an expression (possibly a sub-expression) is expected. int n = ({ // Error 160 here int y = foo (); int z; if (y > 0) z = y; else z = - y; z; }) // Now n has the last value of z. The primary intention of this message is to alert the user to the non-standard nature of this construct. The typical response is to suppress the message and go on. But a few caveats are in order. Programmers who intend to work only with C code with the GNU extensions may safely disable this diagnostic but C++ users should think twice. This is partly for the reasons given in GCC's documentation (see the section entitled "Statements and Declarations in Expressions") and partly because the meaning of '( {' will change in G++ when its maintainers implement Initializer Lists (a new core language feature that is expected to appear in the 2010 version of the ISO C++ Standard). 326 String 'String ...' too long, exceeds Integer characters -- A string (first 40 characters provided in the message) exceeds some internal limit (provided in the message). There is no antidote to this condition in the form of an option. FlexeLint customers may recompile with a redefinition of either M_STRING (maximum string) or M_NAME (maximum name). To override the definition in custom.h we suggest recompiling with an appropriate -dvar=value option assuming your compiler supports the option. 449 Pointer variable 'Symbol' previously deallocated -- A pointer variable (designated in the message) was freed or deleted in an earlier statement. 452 typedef Symbol 'Symbol' redeclared (TypeDiff) conflicts with Location", -- A typedef symbol is being declared to be a different type. This can be legal, especially with multiple modules, but is not good programming practice. It interferes with program legibility. 520 Highest operator or function lacks side-effects -- The first expression of a for clause should either be one of the privileged operators: assignment, increment, decrement or call to an impure function or one modifying its argument(s). 521 Highest operator or function lacks side-effects -- The third expression of a for clause should either be one of the privileged operators: assignment, increment, decrement or call to an impure function or one modifying its argument(s). 522 Highest operator or function lacks side-effects -- If a statement consists only of an expression, it should either be one of the privileged operators: assignment, increment, decrement or call to an impure function or one modifying its argument(s). For example if operator * is the built-in operator, the statement *p++; draws this message but p++; does not. This is because the highest operator is '*' which has no side effects. See the pure semantic in section 584 Trigraph sequence (??Char) detected -- This message is issued whenever a trigraph sequence is detected and the trigraph processing has been turned off (with a -ftg). If this is within a string (or character) constant then the trigraph nature of the sequence is ignored. That is, three characters obtain rather than just one. This is useful if your compiler does not process trigraph sequences and you want linting to mirror compilation. Outside of a string we issue the Warning but we do translate the sequence since it cannot make syntactic sense in its raw state. 660 Option 'String' requests removing an extent that is not on the list -- A number of options use the '-' prefix to remove and '+' to add elements to a list. For example to add (the most unusual) extension .C++ to designate C++ processing of files bearing that extension, a programmer should employ the option: +cpp(.C++) However, if a leading '-' is employed (a natural mistake) this warning will be emitted. 686 Option 'String' is suspicious because of 'Name' -- An option is considered suspicious for one of a variety of reasons. The reason is designated by a reason code that is specified by Name. At this writing, the only reason code is 'unbalanced quotes'. 814 useless declaration -- A tagless struct was declared without a declarator. For example: struct { int n; }; Such a declaration cannot very well be used. 830 Location cited in prior message -- This message is accurately described in the manual except for one omission. This message and message 831 below do not follow the ordinary rules for message suppression. If they did then when the option -w2 was employed to turn the warning level down to 2 these messages (at level 3) would also vanish. Instead they continue to function as expected. To inhibit them you need to explicitly turn them off using one of: -e830 -e831 They may be restored via +e830 and +e831; the state of suppression can be saved and restored via the -save -restore options. Options such as -e8* and -e{831} will have no effect. 831 Reference cited in prior message -- See 830 above. 960 Violates MISRA Year Required Rule Name, String -- MISRA is the "Guidelines for the use of the C Language in Vehicle Based Software". [9,33] The first version of the MISRA Standard was released in 1998 and the second in 2004. Lint references the rules from each version of the Standard using integers for 1998 and in decimal form for 2004, as per the Standard numbering style. The list of required checks made for both MISRA 1998 and 2004 are: Octal constant used (Rule 19/7.1). Should initialize either all enum members or only the first (Rule 32/9.3). Side effects on right hand side of logical operator (Rule 33/12.4). Comma operator used outside of 'for' expression (Rule 42/12.10). Null statement not in line by itself (Rule 54/14.3). continue statement should not be used (Rule 57/14.5). Left brace expected for if, else, for, do, and while (Rules 59/14.8 & 14.9). Floating point variable used as loop counter (Rule 65/13.4). Function not declared at file scope (Rule 68/8.6). Function has variable number of arguments (Rule 69/16.1). Either all parameters or no parameters should have identifiers (Rule 73/16.3). '#define/#undef' used within a block (Rule 91/19.5). Multiple use of '#' and/or '##' operators in macro definition (Rule 98/19.12). Non-standard use of 'defined' preprocessor operator (Rule 100/19.14). Required checks made exclusively for MISRA 1998 are: break used outside of a switch (Rule 58). Header file name contains non-standard non-standard character (Rule 88). Bitfields inside union (Rule 110). Required checks made exclusively for MISRA 2004 are: No definitions of objects or function in header files (Rule 8.5). Prohibited implicit conversion (Rules 10.1 & 10.2). Prohibited cast of complex expressions (Rules 10.3 & 10.4). Recasting required for operators '~' and '<<' (Rule 10.5). 'sizeof' used on expressions with side effect (Rule 12.3) Bitwise operator applied to signed underlying type (Rule 12.7). Prohibited operator applied to unsigned underlying type (Rule 12.9). More than one 'break' terminates loop (Rule 14.6). No 'else' at end of 'if ... else if' chain (Rule 14.10). Boolean value in switch expression (Rule 15.4) Unions shall not be used (Rule 18.4). Use of '#undef' prohibited (Rule 19.6) MISRA 1998 checking is achieved using the -misra(1) option. For MISRA 2004 checks, use -misra(2). You may disable individual rules to your taste by using the Rule number in an esym option. For example: -esym( 960, 75, 8? ) will suppress MISRA rules 75 and any of the those between 80 and 89 inclusive that are issued as the result of a 960. See [9,33] for information on the MISRA guidelines 961 Violates MISRA Year Advisory Rule Name, String" -- This message is issued for some violations of the MISRA advisory guidelines. Certain rules were advisories in the 1998 Standard and became required for the 2004 Standard and vice versa. Therefore, you might see some rules repeated here already listed above for message 960. The list of advisory checks made for both MISRA 1998 and 2004 are: Dependence placed on C's operator precedence (Rule 47/12.1) Only preprocessor statements and comments before '#include' (Rule 87/19.1). Advisory checks made exclusively for MISRA 1998 are: Constant requires numerical suffix (Rule 18) 'register' class discouraged (Rule 28) 'sizeof' used on expressions with side effect (Rule 40) Redundant explicit casting (Rule 44) Non-case label (Rule 55) No 'else' at end of 'if ... else if' chain (Rule 60). Boolean value in switch expression (Rule 63) Use of '#undef' is discouraged (Rule 92) Advisory checks made exclusively for MISRA 2004 are: Header file name contains non-standard non-standard character (Rule 19.2). No use of '#' or '##' (Rule 19.13). Messages can be suppressed based on rule number. See also Message 960. 1076 Anonymous union assumed to be 'static' -- Anonymous unions need to be declared static. This is because the names contained within are considered local to the module in which they are declared. 1079 Could not find '>' or ',' to terminate default template parameter at Location -- A default template parameter was found but it could not be parsed. 1083 Ambiguous conversion between 2nd and 3rd operands of conditional operator -- If the 2nd operand can be converted to match the type of the 3rd, and the 3rd operand can be converted to match the type of the 2nd, then the conditional expression is considered ill-formed. 1085 Invalid definition of 'String' -- An attempt was made to define a member of a template before the template was defined. Example: template struct A { void f(); }; template void A::f(){} // Error 1085 In this case, the template argument list is out of order; T and U have been interchanged. 1093 A pure specifier was given for function 'Symbol' which was not declared virtual -- A pure specifier ("= 0") should not be placed on a function unless the function had been declared "virtual". 1549 Exception thrown for function 'Symbol' not declared to throw -- An exception was thrown (i.e., a throw was detected) within a function and not within a try block; moreover the function was declared to throw but the exception thrown was not on the list. If you provide an exception specification, include all the exception types you potentially will throw. [23, Item 14] 1550 exception 'Name' thrown by function 'Symbol' is not on throw-list of function 'Symbol' -- A function was called (first Symbol) which was declared as potentially throwing an exception. The call was not made from within a try block and the function making the call had an exception specification. Either add the exception to the list, or place the call inside a try block and catch the throw. [23, Item 14]. 1560 Uncaught exception 'Name' not on throw-list of function 'Symbol' -- A direct or indirect throw of the named exception occurred within a try block and was either not caught by any handler or was rethrown by the handler. Moreover, the function has an exception specification and the uncaught exception is not on the list. Note that a function that fails to declare a list of thrown exceptions is assumed to potentially throw any exception. 1710 An implicit 'typename' was assumed -- This message is issued when the standard requires the use of 'typename' to disambiguate the syntax within a template where it may not be clear that a name is the name of a type or some non-type. (See C++ Standard [10], Section 14.6, Para 2). Consider: template< class T > class A { T::N x; // Info 1710 }; Many compilers will accept this construct since the only interpretation consistent with valid syntax is that T::N represents a type. (But if the 'x' weren't there it would be taken as an access declaration and more frequently would be a non-type). ------ Added Bibliography ------ [28] Sutter, Herb, Exceptional C++, Addison-Wesley, Reading MA, 2000, ISBN 0-201-61562-2 [29] Sutter, Herb and Andrei Alexandrescu, C++ Coding Standards (101 Rules, Guidelines, and Best Practices), Addison-Wesley, 2005, ISBN 0-321-11358-6 [30] Meyers, Scott, Effective C++ Third Edition, Addison-Wesley, Reading MA, 2005, ISBN 0-321-33487-6 [31] Lewis, Bil and Daniel J. Berg, Multithreaded Programming with Pthreads, Sun Microsystems Press, 1998, ISBN 0-13-680729-1 [32] Vandevoorde, David and Nicolai M. Josuttis, C++ Templates -- The Complete Guide, Addison-Wesley, Boston, 2003, ISBN 0201734842 [33] The Motor Industry Software Reliability Association, MISRA-C:2004 Guidelines for the use of the C language in critical systems, The Motor Industry Research Association, Warwickshire, UK, 2004, ISBN, 0952415623 Gimpel Software June, 2008