summaryrefslogtreecommitdiff
path: root/reference/C/CONTRIB/SNIP/c_port.txt
diff options
context:
space:
mode:
Diffstat (limited to 'reference/C/CONTRIB/SNIP/c_port.txt')
-rwxr-xr-xreference/C/CONTRIB/SNIP/c_port.txt340
1 files changed, 340 insertions, 0 deletions
diff --git a/reference/C/CONTRIB/SNIP/c_port.txt b/reference/C/CONTRIB/SNIP/c_port.txt
new file mode 100755
index 0000000..bc78baa
--- /dev/null
+++ b/reference/C/CONTRIB/SNIP/c_port.txt
@@ -0,0 +1,340 @@
+
+=====[ Ed Hopper's BBS #1 ]=====[ 8-04-91 ]=====[ 9:55.22 ]=====
+
+
+Date: 08-02-91 (09:40) C-Lang Number: 26406 (Echo)
+ To: ALL
+From: JOSEPH CARNAGE Read: 08-03-91 (10:56)
+City: DUNEDIN FL Last On: 02-28-91 (22:53)
+Subj: Portable, clean code #1
+
+ How to write portable clean source code
+ ---------------------------------------
+
+A common concern with programmers new to Axiom is writing portable
+code. There a number of tricks and guide lines which may help with
+this. In no particular order:
+
+ -- Use full ANSI prototypes with all arguments declared. For
+ function pointers, declare their expected arguments. For
+ prototypes for functions which accept function pointers, do not
+ declare the expected arguments for the function pointer
+ argument.
+
+ It is good practice to put dummy variable names in prototypes as
+ this adds readability.
+
+ -- Explicitly type all variables and functions. Never rely on them
+ defaulting to int.
+
+ -- Pay a little care to the ternary operator ? :, and parenthesize
+ heavily. A very few compilers have problems with the default
+ order of evaluation for the ternary operator.
+
+ -- Never ever name a variable identically to a function. This is
+ most especially true of statics or globals. This sort of error
+ can cause weird hidden linker problems which cause bizarre
+ results at runtime and are difficult to trace.
+
+ -- Never ever name a screen, form, data field etc identically to a
+ variable or function as this can cause weird and non-reported
+ linker errors in the final executable which can be very
+ difficult to locate.
+
+ -- Do not nest comments. If you want to block off a section of
+ code temporarily, use #ifdef/#endif. eg.
+
+ ...code...
+ #ifdef JUNK /* Unwanted code */
+ ...more code...
+ #endif /* JUNK */
+ ...yet more code...
+
+ -- Run PC-Lint on all code, and handle ALL errors and warnings.
+
+ -- Read the "Frequently Asked Questions" document and understand
+ fully.
+
+ -- Read K&R thoroughly and everywhere it mentions "implementation
+ dependant", or "new" features not "supported by all compilers",
+ avoid those areas. Examples are bit fields, passing structures
+ to functions, returning structures from functions, and the
+ volatile type. These are not supported by all compilers.
+
+ -- In areas where the ANSI standard advances on the old K&R, but
+ still allows the K&R form, follow K&R. An example is using
+ function pointers. If you are unsure what areas this covers,
+ don't worry, just stick with K&R. eg.
+
+ Given:
+
+ int (*prj_afunc) (); /* Pointer to function which returns int */
+
+ ANSI allows the pointed to function be called as so:
+
+ prj_afunc (xxx, yyy);
+
+ K&R specifies that it should be called:
+
+ *prj-afunc (xxx, yyy);
+
+ Use the K&R form, which ANSI still allows, and all compilers
+ support.
+
+ -- Do not use the new // comments. Stay with the /* comment */
+ form.
+
+ -- Do not indent #ifdefs, #defines, #pragmas, or other preprocessor
+ directives. Some compilers allow code as such:
+
+ #ifdef DEBUG
+ #define TEST 1
+ #endif
+
+ or
+
+ #ifdef FINAL
+ # ifdef DEBUG
+ # define TEST 1
+ # endif
+ #endif
+
+ But by no means all. Use white space if needed to delineate
+ #ifdef/endif blocks and comment liberally:
+
+ #ifdef FINAL
+
+ #ifdef DEBUG
+ #define TEST 1
+ #endif /* DEBUG*/
+
+ #endif /* FINAL */
+
+ -- Do not use the ANSI string literal concatenation features. eg.
+
+ printf ("This is ANSI but"
+ "unportable code.\n");
+
+ for long string literals. Under ANSI the the compiler should
+ concatenate the two string literals into one, but not all ANSI
+ compilers support this feature yet. If you need a very long
+ string literal use a form as so:
+
+ printf ("%s%s",
+ "this is",
+ "portable code.\n");
+
+ or just use a very long string literal.
+
+ -- Stay away from ints except for trash and temp values. Ints vary
+ in size depending upon the memory model under DOS, and legally
+ may be any size between shorts and longs inclusive.
+
+ Try to use shorts or longs if possible, as these are of fairly
+ constant size on most platforms. On most platforms, but by no
+ means all, shorts are usually words and longs word pairs.
+
+ -- Beware of assigning a pointer of one type to a pointer of a
+ higher type. Most platforms seem to insist that the addresses
+ stored in pointers are alligned per the pointer's base type.
+
+ What this means is that the value stored in a pointer to a long,
+ in itself will be alligned as a long is. If longs are alligned
+ on even word boundaries, then so will the value of long pointer.
+
+ This can result in memory allignment errors which can be
+ extremely difficult to track down. Casting will not help.
+
+ DOS has few memory allignment requirements, but for Unix and VMS
+ you can expect types to be alligned to their sizes (see the
+ compiler manuals for specifics). What this means to pointers is
+ that with code such as:
+
+ short *pj2_value; /* Assume that shorts are alligned to words */
+ long *pj4_number; /* and longs to even word boundaries */
+
+ pj4_number = pj2_value;
+
+ that the value assigned to pj4_number may be as far as two bytes
+ different from that in pj2_value. ie
+
+ Let's say that the address stored is pj2_value is:
+
+ *pj2_value == 0000:0006 /* Alligned to word */
+
+ and you make the assignment:
+
+ pj4_number = pj2_value;
+
+ After this, the value of pj4_number will be either 0000:0004,
+ or 0000:0008 to shift it to even word allignment. The
+ direction of the shift seems to be compiler/implementation
+ dependant.
+
+ This bug is often erratic at runtime depending upon the
+ allignment of automatics. This sort of bug is especically
+ difficult to track when coming up from a void pointer.
+
+ -- Be wary of relying on memory allignment in structures and
+ unions. Different compiler implmentations allign differently,
+ and #pragmas or command line arguments to the compiler can
+ change allignment at compile time. See the compiler manuals for
+ specific details.
+
+ This will usually require you to either read in each member
+ individually, or to perform explicit padding when reading
+ structure data from disk. eg. lic1.c & v_lic_pad() in the Axiom
+ library.
+
+ -- Where possible use sizeof(identifier) rather than sizeof(type)
+ or a #defined constant. This can help in tracing down bugs and
+ makes for greater readability. eg.
+
+ #define M_DATA 100
+ short aj2_numbers[M_DATA];
+
+ /* This example requires the reader to remember that
+ aj2_numbers has M_DATA elements, is overly complex, and
+ presumes that aj2_numbers will always be shorts. This code
+ will likely break if anything is later changed. */
+
+ memcpy (aj2_numbers, pj2_input, M_DATA * sizeof (short));
+
+ /* This is ideal -- sizeof(aj2_numbers) will return the total
+ space allocated to the array, no matter what the type may be,
+ or what is changed later. It makes no assumptions of the
+ reader. */
+
+ memcpy (aj2_numbers, pj2_input, sizeof (aj2_numbers));
+
+ -- Beware of comparing structures or unions with functions such as
+ memcmp() as the padding/allignment spaces will have random and
+ likely different values. If you need to compare structures
+ you'll have to do it member by member.
+
+ -- Never assign structures to each other directly. Some compilers
+ allow structure assignments, some don't.
+
+ struct t_data s_struc1;
+ struct t_data s_struc2;
+
+ s_struc2 = s_struc1; /* Unportable code */
+
+ Note however that you can copy structures via pointers as need
+ be:
+
+ struct t_data *ps_struc1;
+ struct t_data *ps_struc2;
+
+ ps_struc1 = xxx;
+ ps_struc2 = yyy;
+
+ *ps_struc2 = *ps_struc1; /* Copy structure 1 to 2 */
+
+ Rather than assigning each member over individually. The
+ functions memcpy() and memmove() are other portable ways.
+
+ -- Beware of passing chars or shorts to functions. These get
+ promoted to ints, and with some compilers problems from there on
+ out abound horrendously. This is especially true of chars where
+ some compilers occassionally extract the wrong byte from the
+ promoted int in the recieving function.
+
+ -- Be careful passing floats to functions as some compilers promote
+ floats to doubles when passing them as an argument. This can
+ cause spurious warnings and and strange side effects.
+
+ -- Explicitly cast assignments and expressions as needed, and
+ carefully watch that you really don't need to make those
+ identifiers of that type originally. While the promotion order
+ is constant across implementations, the size of the types
+ aren't. This can cause difficult side effects.
+
+ If your code needs a lot of casts to get past Lint, then you
+ probably need to rethink some of your approaches.
+
+ -- Take care to cast all #defined constants if in doubt. For large
+ values (longs), always cast as longs, or place an 'L' at the end
+ of the constant. Some compilers handle this area erraticly if
+ left up to them.
+
+ -- Never ever rely on order of evaluation of function parameters.
+ This can occur when listing a funtion call as a parameter to
+ another funtion, or as an unintentional side effect from passing
+ assignments or function calls as parameters.
+
+ char *pc_modify (char *);
+
+ printf ("This string [%s] becomes [%s]\n",
+ pc_string, pc_modify (pc_string)); /* Bad code */
+
+ -- Do not use NULL for anything but pointers. Do not use NULL for
+ string terminations: use the ASCII constant NUL, '\0', or a
+ #defined type which equates to that.
+
+ -- Never EVER pass a #defined macro an incremented or decremented
+ value (++,or --) or an assignment as a parameter. This is
+ because many #defined macros may reference their arguments
+ multiple times. This is especially true of the macros #defined
+ in ctype.h.
+
+ eg.
+
+ #define iscsymf(c) (isalpha(c) || ((c) == '_'))
+
+ If called as so:
+
+ iscsym(var++);
+
+ it will be expanded by the preprocessor to:
+
+ (isalpha(var++) || ((var++) == '_'))
+
+ with var being incremented twice.
+
+ -- Avoid passing any functions incremented or decremented values
+ ("++" or "--"), or assignments. Some standard and commercial
+ library calls are actually #defined macros. This type of
+ "error" can lead to order of evaluation problems as different
+ compilers process function arguments in different orders.
+
+ -- Explicitly initialise pointers. Do not rely on calloc(),
+ memset() or other such functions to initialise pointers.
+ Initialise them explicitly.
+
+"K&R" as mentioned above refers to "The C Programming Language"
+written by Brian W Kernighan & Dennis M Ritchie.
+
+"PC-Lint" is a commercial version of Lint for the PC, as sold by
+Gimpel Software. PC-Lint is generally acknowledged as the tightest
+and most discerning Lint on any platform.
+
+There are several books which cover the areas of portable code which
+may also help:
+
+ "C Programming Guidelines"
+ by Thomas Plum
+ pub. by Plum Hall
+ ISBN 0-911537-03-1
+
+ "Portability and the C Language"
+ by Rex Jaeschke
+ pub. by Hayden Books
+ ISBN 0-672-48428-5
+
+ "Portable C Software"
+ by Mark R. Horton
+ pub. by Prentice Hall
+ ISBN 0-13-868050-7
+
+ "Portable C"
+ by Henry Rabinowitz & Chaim Schaap
+ pub. by Prentice Hall
+ ISBN 0-13-685967-4
+
+ "Portable C and Unix System Programming"
+ by J.E. Lapin
+ pub. Prentice-Hall
+ ISBN 0-13-686494-5
+
+[END]