Xref: utzoo comp.lang.c:34418 comp.misc:10676 comp.std.c:3985 comp.unix.misc:659 comp.unix.questions:27298 Path: utzoo!censor!geac!torsqnt!news-server.csri.toronto.edu!cs.utexas.edu!uunet!brunix!gvr From: gvr@cs.brown.edu (George V. Reilly) Newsgroups: comp.lang.c,comp.misc,comp.std.c,comp.unix.misc,comp.unix.questions Subject: Notes on Writing Portable Programs in C: part2.tex Summary: Second half of portableC.tex Message-ID: <58027@brunix.UUCP> Date: 30 Nov 90 07:35:43 GMT Sender: news@brunix.UUCP Reply-To: gvr@cs.brown.edu (George V. Reilly) Organization: Brown University Department of Computer Science Lines: 842 % You must concatenate part1.tex and part2.tex together to form % portableC.tex before LaTeXing. %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \section{Using Floating-Point Numbers} %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ To say that the implementation of numerical algorithms that exhibit the same behavior across a wide variety of platforms is difficult, is an understatement. This section provides very little help but we hope it is worth reading. Any additional suggestions and information are {\em very much\/} appreciated as we would like to expand this section. %============================================================================= \subsection{Machine Constants} %============================================================================= One problem when writing numerical algorithms is obtaining machine constants. Typical values one needs are: \begin{itemize} \item The radix of the floating-point representation. \item The number of digits in the floating-point significand expressed in terms of the radix of the representation. \item The number of bits reserved for the representation of the exponent. \item The smallest positive floating-point number $\epsilon$ such that $ 1.0 + \epsilon \neq 1.0$. \item The smallest non-vanishing normalized floating-point power of the radix. \item The largest finite\footnote{Some representations have reserved values for $+{\it inf}$ and $-{\it inf}$.} floating-point number. \end{itemize} On Suns, they can be obtained in \file{}. The ANSI~C Standard recommends that such constants be defined in the header file \file{}. Suns and standards apart, these values are not always readily available, \e.g. in Tektronix workstations running UTek. One solution is to use a modified version of a program that can be obtained from the network which is called \cmd{machar}. \cmd{Machar} is described in \cite{machar} and can obtained by anonymous FTP from the \id{netlib}.\footnote{Email (Internet) address is \id{netlib@ornl.gov}. For more information, send a message containing the line \ to that address.} It is straightforward to modify the C~version of \cmd{machar} to generate a C~preprocessor file that can be included directly by C~programs. There is also a publicly available program called \file{config.c\/} that attempts to determine many properties of the C~compiler and machine that it is run on. It can generate the ANSI~C header files \file{} and \file{} among other useful features. This program was submitted to \ng{comp.sources.misc}.\footnote{The archive site of \ng{comp.sources.misc} is \site{uunet.uu.net}.} The latest version, 4.2, is available by FTP from \site{mcsun.eu.net} in directory \file{misc} and is called \file{config42.c} (the next version, 4.3, will be called \file{enquire.c}). Version~4.2 is also distributed with \cmd{gcc}, where it is called \file{hard-params.c}. %============================================================================= \subsection{Floating-Point Arguments} %============================================================================= In the days of K\&R {\cite{KR1}} one was ``encouraged'' to use \ and \ interchangeably\footnote{In fact one wonders why they even bothered to define two representations for floating-point numbers considering the rules applied to them.} since all expressions with such data types where always evaluated using the \ representation --- a real nightmare for those implementing efficient numerical algorithms in~C\@. This rule applied, in particular, to floating-point arguments and for most compilers around, it does not matter whether one defines the argument as \ or \. According to the ANSI~C Standard, such programs will continue to exhibit the same behavior {\em as long as one does not prototype the function}. Therefore, when prototyping functions, make sure that the prototype is included when the function definition is compiled so the compiler can check if the arguments match. %============================================================================= \subsection{Floating-Point Arithmetic} %============================================================================= Be careful when using the \<==> and \ operators to compare floating-point types. Expressions such as \begin{center} \ \end{center} will seldom be satisfied due to {\em rounding errors}. To get a feeling about rounding errors, try evaluating the following expression using your favorite C~compiler \cite{fparith}: \[ 10^{50} + 812 - 10^{50} + 10^{55} + 511 - 10^{55} = 812 + 511 = 1323 \] Most computers will produce zero regardless of whether one uses \ or \. Although the {\em absolute error\/} is large, the {\em relative error\/} is quite small and probably acceptable for many applications. It is rather better to use expressions such as $\left| \fe1 - \fe2 \right| \leq K$ or $\bigl| \left| {\fe1}/{\fe2} \right| - 1.0 \bigr| \leq K$ (if $\fe2 \neq 0.0$), where $0 < K < 1$ is a function of: \begin{enumerate} \item The floating type, \e.g. \ or \, \item the machine architecture (the machine constants defined in the previous section), and \item the precision of the input values and the rounding errors introduced by the numerical method used. \end{enumerate} Other possibilities exist and the choice depends on the application. The development of reliable and robust numerical algorithms is a very difficult undertaking. Methods for certifying that the results are correct within reasonable bounds must usually be implemented. A reference such as \cite{NRC} is always useful. \begin{itemize} \item Keep in mind that the \ representation does not necessarily increase the {\em precision}. Actually, in some implementations the precision decreases, but the {\em range\/} increases. \item Do not use \ unnecessarily, since in many cases there is a large performance penalty. Furthermore, there is no point in using higher precision, if the additional bits that would be computed are garbage anyway. The precision one needs depends mostly on the precision of the input data and the numerical method used. \end{itemize} %============================================================================= \subsection{Exceptions} %============================================================================= Floating-point exceptions (overflow, underflow, division by zero, etc) are not signaled automatically in some systems. In that case, they must be explicitly enabled. {\em Always\/} enable floating-point exceptions, since they may be an indication that the method is unstable. Otherwise, one must be sure that such events do not affect the output. %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \section{VMS} %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ In this section, we will report some common problems encountered when porting a C~program to a VMS environment and which we have not mentioned previously. %============================================================================= \subsection{File Specifications} %============================================================================= Under VMS, one can use two flavors of command interpreters: DCL and DEC/Shell. The syntax of file specifications under DCL differs significantly from the Unix syntax. Some C~run-time library functions in VMS that take file specifications as arguments or return file specifications to the caller, will accept an additional argument indicating which syntax is preferred. It is useful to use these run-time library functions via macros as follows: \begin{verbatim} #ifdef VMS # ifndef VMS_CI /* Which Command Interpreter to use */ # define VMS_CI 0 /* 0 for DEC/Shell, 1 for DCL */ # endif # define Getcwd(buff,siz) getcwd((buff),(siz),VMS_CI) # define Getname(fd,buff) getname((fd),(buff),VMS_CI) # define Fgetname(fp,buff) fgetname((fp),(buff),VMS_CI) #else /* !VMS */ # define Getcwd(buff,siz) getcwd((buff),(siz)) # define Getname(fd,buff) getname((fd),(buff)) # define Fgetname(fp,buff) fgetname((fp),(buff)) #endif /* !VMS */ \end{verbatim} More pitfalls await the unaware who accept file specifications from the user or take them from environment values (\e.g. using the \ function). %============================================================================= \subsection{Miscellaneous} %============================================================================= \begin{description} \item[\, \, \:] these global symbols are not available under VMS\@. \item[\ assignments:] VAX~C allows assignment of different types of \s if both types have the same size. {\em This is not a portable feature.} \item[The system function:] the \ function under VMS has the same {\em functionality\/} as the Unix version, except that one must take care that the command interpreter also provides the same functionality. If the user is using DCL, then the application must send a DCL-like command. \item[The linker:] what follows applies only to modules stored in libraries.\footnote{This does not really belong in this document, but whenever one is porting a program to a VMS environment one is bound to come across this strange behavior which can result in a lot of wasted time.} If none of the global {\em functions\/} are explicitly used (referenced by another module), then the module is not linked {\em at all}. It does not matter whether one of the global {\em variables\/} is used. As a side effect, the initialization of variables is not done. The easiest solution is to force the linker to add the module using the \cmd{/INCLUDE} command modifier. Of course, there is the possibility that the command line may exceed 256~characters\ldots(*sigh*). \end{description} %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \section{General Guidelines} %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %============================================================================= \subsection{Types and Pointers} \label{tp} %============================================================================= \begin{description} \item[Type sizes:] {\em Never\/} make any assumptions about the size of a given type, especially pointers \cite{style}. Statements such as \ make implicit use of the size of~\. If the intention is to clear the lowest three bits, then it is best to use \. The first alternative will also clear the high-order 16~bits if~\ is 32~bits wide. \item[Byte ordering:] \label{byteorder} There are two possibilities for byte ordering: {\em little-endian\/} and {\em big-endian\/} architectures. This problem is illustrated by the code below: \begin{verbatim} long int str[2] = {0x41424344, 0x0}; /* ASCII "ABCD" */ printf ("%s\n", (char *)&str); \end{verbatim} A little-endian (\e.g. VAX) will print ``\'' whereas a big-endian (\e.g. MC68000 microprocessors) will print ``\''\@. (As a side note, there is also {\em PDP-endian\/} that would print ``\'', followed by many smileys.) Note: The example will only function correctly if \ is 32~bits. Although not portable, it serves well as an example for the given problem. \item[Alignment constraints:] Beware of alignment constraints when allocating memory and using pointers. Some architectures restrict the addresses that certain operands may be assigned to (that is, addresses of the form~$2^kE$, where~$k > 0$). Code such as \begin{verbatim} char *s = "bla"; /* allocated by compiler */ int *v = (int *)s; \end{verbatim} would most probably fail if the alignment constraints of \ types are more strict than those of \ types (the usual case for RISC architectures). The code would not fail due to alignment constraints if the memory indicated by~\ had been allocated by \ and friends. \item[Pointer formats:] \cite{style} Pointers to objects may have the same size but different formats. This is illustrated by the code below: \begin{verbatim} int *p = (int *) malloc(...); ... free(p); \end{verbatim} This code may malfunction in architectures where \ and \ have different representations because \ expects a pointer of the latter type. Pointers to different types of objects may have different sizes as well. For instance, there are platforms where a \ is larger than an \ or where a pointer to a function will not fit in, \e.g. \ or \ (although such cross-assignments work on many platforms, \ is only guaranteed to be large enough to hold a pointer to any {\em data\/} object). Therefore, it is not portable to assign to an object of type \ a pointer to a function. Pointers to functions are further discussed below. \item[Pointers to functions] If you need a generic function pointer, then use \. Be sure to cast the pointer back to the original type before using it. That is, the type signature of the function pointer at the point that the function is called must {\em exactly\/} match the type signature at the point at which the function is defined. For example, it is not possible to (portably) use \ functions\footnote{There is a difference between variadic functions defined by the Standard and the pre-Standard \ as defined by \file{varargs.h} which is still widely used. Here we are referring to the former, and the differences between both are explored in~\S\ref{ansic}.} (that is, functions that take a variable number of arguments) and fixed-argument functions interchangeably, even if the overlapping types match (that is, even if the first~$n$ arguments to the fixed-argument function are the same as the first~$n$ arguments to the \ function). For instance, a function that is declared as having an integer as the first argument and an optional (integer) second argument cannot be called as a function that takes two integer arguments. Similarly, \ functions of various type signatures cannot be interchanged. Such type cheating will break on systems that use different conventions for calling fixed-argument and \ functions and on systems that use different conventions for passing the fixed and \ parts of the argument lists. As a corollary, it is necessary that the definitions of external variadic functions be available at the point of their usage, \e.g. library functions such as \. \item[Pointer operators:] \cite{style} Only the operators \<==> and \ are defined for all pointers of a given type. The remaining comparison operators (\<<>, \<<=>, \<\GT>, and \<\GE>) can only be used when both operands point into the same array or to the first element after the array. The same applies to arithmetic operators on pointers.\footnote{One of the reasons for these rules is that in some architectures, pointers are represented as a pair of values and only equality is a well-defined operator for arbitrary pairs of values. The other operators are only well-defined when one of the values of both pairs is guaranteed to match, in which case the situation is analogous to ``ordinary'' architectures.} \item[\ pointer:] {\em Never\/} redefine the \ symbol. The \ symbol should always be the {\em constant\/} zero. A null pointer of a given type will always compare equal to the {\em constant\/} zero, whereas comparison with a {\em variable\/} with value zero or to some non-zero constant has implementation-defined behavior. (In other words, the constant zero has two meanings.) A null pointer of a given type will always convert to a null pointer of another type if implicit or explicit conversion is performed. (See `Pointer Operators' above.) The contents of a null pointer may be anything the implementor wishes, and dereferencing it may cause strange things to happen\ldots. \end{description} %============================================================================= \subsection{Compiler Differences} %============================================================================= %----------------------------------------------------------------------------- \subsubsection{Conversion Rules} %----------------------------------------------------------------------------- In arithmetic expressions, integral types may be converted in two ways: {\em unsigned-preserving\/} or {\em value-preserving}. In the unsigned-preserving model, \s, \s, and bit-fields are converted to \ or \ if the original types have the modifiers \ or \, respectively. The Standard determines that the value-preserving model must be used, meaning that \ values are promoted to \, or simply \, if it can represent all the values of the original type; otherwise it is converted to \. (See \S3.2 of the Standard.) The following example illustrates the problem. On a machine with a 16-bit \, and 32-bit \, the code fragment \begin{verbatim} unsigned short int x = 1; if (x < -1) printf ("unsigned-preserving"); else printf ("value-preserving"); \end{verbatim} prints \ or \ accordingly. Plenty of other examples can be derived, such as initializing~\ with~$2^{15}$ and using the predicate \<(x*x*2~\GT~0)>. The expression \ would probably result in the same bit pattern in both models but would cause arithmetic overflow in the value-preserving model. %----------------------------------------------------------------------------- \subsubsection{Compiler Limitations} %----------------------------------------------------------------------------- % particularly IBM PC, GNU Compiler on Sun-4's, VMS compiler, etc. In practice, much too frequently one runs into several, unstated compiler limitations: \begin{itemize} \item Some of these {\em limitations\/} are {\em bugs}. Many of these bugs are in the optimizer and therefore when dealing with a new environment it is best to explicitly disable optimization until one gets the application ``going''. \item Some compilers cannot handle large modules or ``large'' statements.\footnote{Programs that generate other programs, \e.g. \cmd{yacc}, can generate, for instance, very large \ statements.} Therefore, it is advisable to keep the size of modules within reasonable bounds. Besides, large modules are more cumbersome to edit and understand. \end{itemize} % arl: o MSC has serious problem .. when you write big modules, or % yacc or other generator generates them, compiler can't % handle them ... ugh % o MSC can't also handle big switch statements ... so if % you want to write big state machine ... tough luck %----------------------------------------------------------------------------- \subsubsection{ANSI~C}\label{ansic} %----------------------------------------------------------------------------- The Standard has introduced and officialized current practice, but as we all know not many compilers conform to the Standard. Among the features that are not yet widely supported, we mention here only a few: \begin{description} \item[Constant suffixes:] Many compilers allow for suffixes to be appended to constants, such as~\<10L> to indicate a \ constant. The Standard allows further typing of constants, such as~\<10UL> to indicate an \ constant. However, multiple suffixes are not supported by many compilers. \item[New types:] Besides the type \ which is mentioned in the next section, the Standard has introduced the type \. \item[Variadic functions:] Variadic functions, as defined by the Standard, differ significantly from \file{}. Besides the ellipsis notation, it is required by the Standard that the first argument be identified and that \file{} be used instead (see~\S\ref{varargsh}). Therefore, it is not possible to define a variadic function which takes no arguments. \end{description} %----------------------------------------------------------------------------- \subsubsection{Miscellaneous}\label{misc} %----------------------------------------------------------------------------- \begin{description} \item[\ types:] When \ types are used in expressions, most implementations will treat them as \ {\em but there are many others that treat them as\/ \} (\e.g. VAX~C and HP-UX). It is advisable to always cast \s when they are used in arithmetic expressions. \item[Initialization:] Do not rely on the initialization of \ variables and of memory returned by \. In particular, since not all \ pointers are represented by a bit pattern of all-zeroes, it is good practice to always initialize pointers appropriately. The \ library function returns an area of memory that has been cleared to zero. Although this can be used to initialize arrays and \s on many architectures, not all architectures represent \ pointers internally with a zero bit-pattern. Similarly, it is not safe to assume that all architectures represent the floating-point constant~\<0.0> using a zero bit-pattern. The semantics of many library functions differ from system to system. Also, the specifications of some library functions have been changed in the ANSI~C Standard. For example, \ is now required to behave like \ when called with a \ argument; formerly, many implementations would dump core if handed \\@. \item[Bit fields:] Some compilers, \e.g. VAX~C, require that bit fields within \s be of type \ or \. Furthermore, the upper bound on the length of the bit field may differ among different implementations. \item[\] \begin{enumerate} \item The result of \ may be \ or \. \item If~\

is a pointer, then \ is allowed by the Standard and many compilers even if~\

does not contain a valid address such as \\@. However, some compilers dereference the pointer causing programs to crash. \end{enumerate} \item[\ and \:] Some very old compilers do not recognize \ [{\em sic\/}]. Although required by the Standard, some compilers recognize \ but fail to recognize \. The following code might prove useful: \begin{verbatim} #if __STDC__ # define HAS_VOIDP #endif #ifdef HAS_VOIDP typedef void *voidp; #else typedef char *voidp; #endif \end{verbatim} \item[Functions as arguments:] When calling functions passed as arguments, always dereference the pointer. In other words, if~\ is a pointer to a function, use~\<(*f)()> instead of simply~\<(f)()>, because some compilers may not recognize the latter. \item[String constants:] Do not modify string constants since many implementations place them in read-only memory. Furthermore, that is what the Standard requires --- and that is how a constant should behave! Note: In statements such as ``\'', \<"string"> is a string constant, whereas in ``\ it is not and it is legal to modify~\. \item[\ comparisons:] Some compilers might allow for \s to be compared for equality or inequality. Such an extension is not included in the Standard (meaning it is not portable). \item[Initialization of aggregates:] Some compilers cannot initialize \ aggregate types. Statements such as: \begin{verbatim} { typedef struct {double x,y} Interval; Interval range = {0.0,0.0}; ... } \end{verbatim} are not allowed by some compilers unless the modifier \ is used or if \ has file scope. Although declaring all such variables \ would handle most situations, the most portable solution is to add code that performs the initialization. \item[Nested comments:] Nested comments were never allowed in the C~language, but they are allowed by some compilers. Nested comments are used by some to comment out source code containing comments. However, the same effect can be obtained using an \<\#if~0> and \<\#endif> pair. \item[Shift operators:] When shifting \s right, the vacated bits might be filled with zeroes or with copies of the sign bit. \s will be filled with zeroes. \item[Division and remainder:] When both operands are non-negative, then the remainder is non-negative and smaller than the divisor; if not, it is guaranteed only that the absolute value of the remainder is smaller than the absolute value of the divisor. % See K&R II, p. 205 \end{description} %============================================================================= \subsection{Files} %============================================================================= %----------------------------------------------------------------------------- \subsubsection{General Guidelines} %----------------------------------------------------------------------------- Remember that not all operating systems share Unix's simple notion of a file as a stream of bytes. MS-DOS, for instance, has text files and binary files; it is important to open files in the correct mode. VMS has many different file types and each file is viewed as being a collection of structured records. % RMS == Horror-Mess! MS-DOS provides a ``poor man's'' implementation of pipes and redirection. It does not expand wildcards, however. The user must do the wildcard expansion using \ and \. Under VMS, the user must also expand wildcards, and parse \ for redirection directives manually. % I think that all of the above is correct. Actually, DECUS C can do % redirection and wildcard expansion automatically, I think. Different operating systems use widely different syntax to specify pathnames. This is a potential source of problems. Some compilers may provide run-time pathname translation to translate between Unix syntax and the host's syntax. %----------------------------------------------------------------------------- \subsubsection{Source Files} %----------------------------------------------------------------------------- \begin{itemize} \item Keep files reasonably small in order not to upset some compilers. \item File names should not exceed 14~characters (many System~V-derived system impose this limit, whereas in BSD-derived systems a limit of~15 is usually the case). In some implementations this limit can be as low as 8~characters. These limits are often {\em not\/} imposed by the operating system but by system utilities such as \cmd{ar}. \item Do not use special characters especially multiple dots (dots have a very special meaning under VMS). \end{itemize} %============================================================================= \subsection{Miscellaneous} %============================================================================= \begin{description} \item[System dependencies:] Isolate system-dependent code in separate modules and use conditional compilation. \item[Utilities:] Utilities for compiling and linking such as \cmd{Make} simplify considerably the task of moving an application from one environment to another. Even better, use \cmd{Imake} since \cmd{Make} files are very unportable. \cmd{Imake} is distributed with the X~Window System by MIT\@. One of the authors of this document has used it extensively with very good results. Many of the tools and libraries that one takes for granted on Unix, such as \cmd{lex}, \cmd{yacc}, \cmd{curses}, \cmd{sed}, \cmd{awk}, and the various shells, are often not available on other operating systems. Public-domain versions of most of the useful tools are available at many archive sites. However, the so-called copyleft restrictions on many of these programs may prove to be problematic to some would-be porters. % I think, correct me if I'm wrong! \item[Name space pollution:] Minimize the number of global symbols in the application. One of the benefits is the lower probability that any conflicts will arise with system-defined functions. \item[Character sets:] Do not assume that the character set is ASCII\@. If the character set in question is not [American] English, then other characters will also be alphabetic, and their lexicographic ordering will not necessarily have any relationship to their positions within the character set. If the character set is Asian, then ``characters'' may be of type \, not \, and will, in general, require two or more bytes of storage each. The library string functions should be capable of handling these correctly. Code that iterates through arrays of \s may need to be changed to handle multibyte characters correctly. If the program's messages are likely to be translated into other languages, take care to modularize the code for easy translation. Consider keeping all text in a ``language'' file. Be aware that carefully formatted reports and printing routines may need major surgery. % Finns must know more about this stuff than most Anglophones! \item[Binary Data:] Great care must be taken when reading and writing binary data. For example, a file of floating-point numbers in binary format written by machine~$A$ is unlikely to be usable on machine~$B$. \end{description} %============================================================================= \subsection{Writing Portable Code} %============================================================================= Write code under the assumption that it will be ported to many strange machines. It is considerably easier to port code to a new environment when the code has been written with porting in mind, than it is to ``retrofit'' portability. One school of thought advocates ``Port early, port often.'' That is, whenever the code reaches a certain level of stability on the development system, port it to other systems. This method has the advantage that portability problems are discovered early, and the possible disadvantage that potentially far more time could be spent in porting than would be the case if the code were just ported once, when complete. Code in ANSI~C whenever possible. Many of the extensions --- prototypes, stronger type-checking, etc.\ --- enhance portability. The more widely ANSI~C is used, the quicker it will gain acceptance. Of course, this may not be an option if the code must be ported to platforms without ANSI~C compilers. The short-term solution is to use the various tricks discussed in~\cite{style} and elsewhere; the long-term solution is to force vendors to release ANSI~C compilers for their systems. Alternatively, a converter such as \cmd{protoize} (available via anonymous FTP from \site{prep.ai.mit.edu}) can convert between ANSI and non-ANSI programs. Make complete, correct declarations; don't let parameters default to \. Include all of the necessary header files. Declare functions with no return value as \. Check the results of system calls. Use \cmd{lint}. Programs that fail to pass \cmd{lint} quietly will undoubtedly be difficult to port. Compile code with as many different compilers as possible with all warnings enabled. \cite{style} has more to say about this. %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \section{Further Reading} %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ One can argue that portability and ``well-written'' code go hand-in-hand. Loosely defined, well-written code is one that is ``easy'' to understand {\em and\/} ``easy'' to maintain, and there are several style guides in the public domain expressing various views on the subject. Besides the style guide mentioned in the foreword, there are a few more that can be obtained in \site{cs.toronto.edu} [128.100.1.65] in \file{\twiddle{}ftp/doc/programming}. We also recommend \file{standards.text} from the Free Software Foundation which can be found in various sites, \e.g. \site{prep.ai.mit.edu} [18.71.0.38] in \file{\twiddle{}ftp/pub/gnu}. For those who have access to the Usenet newsgroup \ng{comp.lang.c}, we highly recommend reading the Frequently Asked Questions List (known as the {\em FAQL\/}) which is posted at the beginning of every month. %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \section{Acknowledgements} %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ We are grateful for the early help of A.~Louko (HTKK/Lsk) and J.~Helminen (HTKK). The following persons have commented on and corrected previous revisions of this document: Geoffrey H.~Cooper and Guy Harris. Special thanks go to Steven Pemberton, the main author of \file{config.c}, for making available such a useful tool. We thank all the contributors to the Usenet newsgroups \ng{comp.std.c} and \ng{comp.lang.c} from where we have taken a lot of information. Some information within was obtained from \cite{HP}\@. %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \section{Trademarks} %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ { \footnotesize DEC, PDP-7, VMS and VAX are trademarks of Digital Equipment Corporation. \\ HP is a trademark of Hewlett-Packard, Inc.\\ MC68000 is a trademark of Motorola.\\ {\sc PostScript} is a registered trademark of Adobe Systems, Inc.\\ Sun is a trademark of Sun Microsystems, Inc. \\ Unix is a registered trademark of AT\&T\@. \\ X Window System is a trademark of MIT\@.\\ } \newcommand{\newblock}{} \bibliography{portableC} \end{document} Brought to you by Super Global Mega Corp .com