Changes to Answers to Frequently Asked Questions (FAQ) on comp.lang.c
Steve Summit
scs at adam.mit.edu
Fri Mar 1 16:13:29 AEST 1991
This article contains changes between the previous posting of the
frequently-asked questions list (posted on February 6) and the new
one. (Do _not_ worry if you have not seen the new one yet; it's
coming up next.)
(These diffs have been edited for readability and are not suitable
for the patch program.)
==========
< [Last modified February 5, 1991 by scs.]
---
> [Last modified February 28, 1991 by scs.]
==========
> Besides listing frequently-asked questions, this article also summarizes
> frequently-posted answers. Even if you know all the answers, it's worth
> skimming through this list once in a while, so that when you see one of
> its questions unwittingly posted, you won't have to waste time
> answering.
==========
discouraged. (Any object pointer may be cast to the "universal"
pointer type void *, or char * under a pre-ANSI compiler, when
< heterogeneous pointers must be passed around.)
---
> heterogeneous pointers must be passed around.) It is no longer
> guaranteed that a pointer can be cast to a "suitably capacious"
> integer and back, unchanged.
==========
< A: As a stylistic convention, many people prefer not to have unadorned
< 0's scattered throughout their programs. For this reason, the
---
> A: As a matter of style, many people prefer not to have unadorned 0's
> scattered throughout their programs. For this reason, the
==========
< NULL should _only_ be used for pointers. It should not be used when
< another kind of 0 is required, even though it might work, because
< doing so sends the wrong stylistic message. (ANSI allows the
< #definition of NULL to be (void *)0, which will not work in non-
< pointer contexts.) In particular, do not use NULL when the ASCII
< null character (NUL) is desired. Provide your own definition
<
< #define NUL '\0'
<
< if you must.
---
> NULL should _only_ be used for pointers; see question 9.
==========
< A: This trick, though popular with beginning programmers, does not buy
< much.
---
> A: This trick, though popular in some circles, does not buy much.
==========
> "Abbreviations" such as if(p), though perfectly legal, are
> considered by some to be bad style.
==========
< distinguishing pointer 0's from integer 0's. Again, NULL should not
< be used for other than pointers.
---
> distinguishing pointer 0's from integer 0's.
>
> NULL should _not_ be used when another kind of 0 is required, even
> though it might work, because doing so sends the wrong stylistic
> message. (ANSI allows the #definition of NULL to be (void *)0,
> which will not work in non-pointer contexts.) In particular, do
> not use NULL when the ASCII null character (NUL) is desired.
> Provide your own definition
>
> #define NUL '\0'
>
> if you must.
==========
11. I once used a compiler that wouldn't work unless NULL was used.
< A: That compiler was broken. In general, making decisions about a
---
> A: Unless the code being compiled was nonportable (see question 6),
> that compiler was probably broken. In general, making decisions
==========
< This article always uses the phrase "null pointer" for sense 1, the
< character "0" for sense 3, and the capitalized word "NULL" for
< sense 4.
---
> This article always uses the phrase "null pointer" (in lower case)
> for sense 1, the character "0" for sense 3, and the capitalized
> word "NULL" for sense 4.
==========
> 15. Given all the confusion surrounding null pointers, wouldn't it be
> easier simply to require them to be represented internally by
> zeroes?
>
> A: If for no other reason, doing so would be ill-advised because it
> would unnecessarily constrain implementations which would otherwise
> naturally represent null pointers by special, nonzero bit patterns,
> particularly when those values would trigger automatic hardware
> traps for invalid accesses.
>
> Besides, what would this requirement really accomplish? Proper
> understanding of null pointers does not require knowledge of the
> internal representation, whether zero or nonzero. Assuming that
> null pointers are internally zero does not make any code easier to
> write (except for a certain ill-advised usage of calloc; see
> question 57). Known-zero internal pointers would not obviate casts
> in function calls, because the _size_ of the pointer might still be
> different from that of an int. (If "nil" were used to request null
> pointers rather than "0," as mentioned in question 13, the urge to
> assume an internal zero representation would not even arise.)
>
> 16. Seriously, have any actual machines really used nonzero null
> pointers?
>
> A: "Certain Prime computers use a value different from all-
> bits-0 to encode the null pointer. Also, some large
> Honeywell-Bull machines use the bit pattern 06000 to encode
> the null pointer. On such machines, the assignment of 0 to
> a pointer yields the special bit pattern that designates the
> null pointer."
>
> -- Portable C, by H. Rabinowitz and Chaim Schaap,
> Prentice-Hall, 1990, page 147.
>
> The "certain Prime computers" were the segmented 50 series, which
> used segment 07777, offset 0 for the null pointer, at least for
> PL/I. Later models used segment 0, offset 0 for null pointers in
> C, necessitating new instructions such as TCNP (Test C Null
> Pointer), evidently as a sop to all the extant poorly-written C
> code which made incorrect assumptions.
>
> The Symbolics Lisp Machine, a tagged architecture, does not even
> have conventional numeric pointers; it uses the pair <NIL, 0>
> (basically a nonexistent <object, offset> handle) as a C null
> pointer.
==========
16. But I heard that char a[] was identical to char *a.
< A: This identity (that a pointer declaration is interchangeable with an
< array declaration, usually unsized) holds _only_ for formal
< parameters to functions. This identity is related to the fact that
< arrays "decay" into pointers in expressions. That is, when an array
< name is mentioned in an expression, it is converted immediately into
< a pointer to the array's first element. Therefore, an array is
< never passed to a function; rather a pointer to its first element is
< passed instead. Allowing pointer parameters to be declared as
< arrays is a simply a way of making it look as though the array was
< actually being passed. Some programmers prefer, as a matter of
< style, to use this syntax to indicate that the pointer parameter is
< expected to point to the start of an array rather than to some
< single value.
<
< Since functions can never receive arrays as parameters, any
< parameter declarations which "look like" arrays, e.g.
<
< f(a)
< char a[];
<
< are treated as if they were pointers, since that is what the
< function will receive if an array is passed:
<
< f(a)
< char *a;
<
< To repeat, however, this conversion holds only within function
< formal parameter declarations, nowhere else. If this conversion
< bothers you, don't use it; many people have concluded that the
< confusion it causes outweighs the small advantage of having the
< declaration "look like" the call and/or the uses within the
< function.
---
> A: Not at all. (What you heard has to do with formal parameters to
> functions; see question 21.) Arrays are not pointers. The
> declaration "char a[6];" requests that space for six characters be
> set aside, to be known by the name "a." That is, there is a
> location named "a" at which six characters can sit. The
> declaration "char *p;" on the other hand, requests a place which
> holds a pointer. The pointer is to be known by the name "p," and
> can point to any char (or contiguous array of chars) anywhere.
>
> As usual, a picture is worth a thousand words. The statements
>
> char a[] = "hello";
> char *p = "world";
> char *p2 = a;
>
> would result in data structures which could be represented like
> this:
>
> +---+---+---+---+---+---+
> a: | h | e | l | l | o |\0 |
> +---+---+---+---+---+---+
> ^
> |
> +--|--+
> p2: | * |
> +-----+
>
> +-----+ +---+---+---+---+---+---+
> p: | *======> | w | o | r | l | d |\0 |
> +-----+ +---+---+---+---+---+---+
>
> 19. You mean that a reference like x[3] generates different code
> depending on whether x is an array or a pointer?
>
> A: Precisely. Referring back to the sample declarations in the
> previous question, when the compiler sees the expression a[3], it
> emits code to start at the location "a," move three past it, and
> fetch the character there. When it sees the expression p[3], it
> emits code to start at the location "p," fetch the pointer value
> there, add three to the pointer, and finally fetch the character
> pointed to. In the example above, both a[3] and p[3] (and p2[3],
> for that matter) happen to be the character 'l', but that the
> compiler gets there differently. (See also question 100.)
==========
17. So what is meant by the "equivalence of pointers and arrays" in C?
< A: Much of the confusion surrounding pointers in C can be traced to a
< misunderstanding of this statement. Saying that arrays and pointers
< are "equivalent" does not by any means imply that they are
< interchangeable. (The fact that, as formal parameters to functions,
< array-style and pointer-style declarations are in fact
< interchangeable does nothing to reduce the confusion.)
<
< "Equivalence" refers to the fact (mentioned above) that arrays decay
< into pointers within expressions, and that pointers and arrays can
< both be dereferenced using array-like subscript notation. That is,
< if we have
<
< char a[10];
< char *p = a;
< int i;
<
< we can refer to a[i] and p[i]. (That pointers can be subscripted
< like arrays is hardly surprising, since arrays have decayed into
< pointers by the time they are subscripted.)
==========
> A: Much of the confusion surrounding pointers in C can be traced to a
> misunderstanding of this statement. Saying that arrays and
> pointers are "equivalent" does not by any means imply that they are
> interchangeable.
>
> "Equivalence" refers to the following key definition:
>
> An identifier of type array-of-T which appears in an
> expression decays (with three exceptions) into a pointer to
> its first element; the type of the resultant pointer is
> pointer-to-T.
>
> (The exceptions are when the array is the operand of the sizeof()
> operator or of the & operator, or is a literal string initializer
> for a character array.)
>
> As a consequence of this definition, there is not really any
> difference in the behavior of the "array subscripting" operator []
> as it applies to arrays and pointers. In an expression of the form
> a[i], the array name "a" decays into a pointer, following the rule
> above, and is then subscripted exactly as would be a pointer
> variable in the expression p[i]. In either case, the expression
> x[i] (where x is an array or a pointer) is, by definition, exactly
> equivalent to *((x)+(i)).
>
> 21. Then why are array and pointer declarations interchangeable as
> function formal parameters?
>
> A: Since arrays decay immediately into pointers, an array is never
> actually passed to a function. Allowing pointer parameters to be
> declared as arrays is a simply a way of making it look as though
> the array was being passed. Some programmers prefer, as a matter
> of style, to use this syntax to indicate that the pointer parameter
> is expected to point to the start of an array rather than to some
> single value.
>
> Since functions can never receive arrays as parameters, any
> parameter declarations which "look like" arrays, e.g.
>
> f(a)
> char a[];
>
> are treated by the compiler as if they were pointers, since that is
> what the function will receive if an array is passed:
>
> f(a)
> char *a;
>
> To repeat, however, this conversion holds only within function
> formal parameter declarations, nowhere else. If this conversion
> bothers you, don't use it; many people have concluded that the
> confusion it causes outweighs the small advantage of having the
> declaration "look like" the call and/or the uses within the
> function.
==========
> 22. Someone explained to me that arrays were really just constant
> pointers.
>
> A: That person did you a disservice. An array name is "constant" in
> that it cannot be assigned to, but an array is _not_ a pointer, as
> the discussion and pictures in question 18 should make clear.
==========
A: Yes, Virginia, array subscripting is commutative in C. This curious
fact follows from the pointer definition of array subscripting,
namely that a[e] is exactly equivalent to *((a)+(e)), for _any_
< expression e and primary expression a, as long as one of them is a
< pointer expression. This unsuspected commutativity is often
---
> for _any_ expression e and primary expression a, as long as one of
> them is a pointer expression and one is integral. This unsuspected
==========
< Pointers to arrays are confusing, and it is best to avoid them.
---
> Pointers to arrays can be confusing, and must be treated carefully.
==========
In the first declaration, the compiler performs the usual implicit
rewriting of "array of array" to "pointer to array;" in the second
< form the pointer declaration is explicit. The called function does
< not care how big the array is, but it must know its shape, so the
< "column" dimension XSIZE must be included. In both cases the number
< of "rows" is irrelevant, and omitted.
---
> the second form the pointer declaration is explicit. Since the
> called function does not allocate space for the array, it does not
> need to know the overall size, so the number of "rows," YSIZE, can
> be omitted. The "shape" of the array is still important, so the
> "column" dimension XSIZE (and, for 3- or more dimensional arrays,
> the intervening ones) must be included.
==========
The order of other embedded side effects is similarly undefined.
< For example, the expression i + (i = 2) may or may not have the
< value 4.
---
> For example, the expression i + (i = 2) does not necessarily yield
> 4.
==========
> The Rationale, by itself, has been printed by Silicon Press, ISBN
> 0-929306-07-4.
==========
26. Does anyone have a tool for converting old-style C programs to ANSI
C, or for automatically generating prototypes?
< A: There are several such programs, many in the public domain. Check
< your nearest comp.sources archive.
---
> A: Two programs, protoize and unprotoize, are being written to convert
> back and forth between prototyped and "old style" function
> definitions and declarations. (These programs are _not_ expected
> to handle full-blown conversion between "Classic" C and ANSI C.)
> When available, these programs will exist as patches to the FSF GNU
> C compiler, gcc.
>
> Several prototype generators exist, many as modifications to lint.
==========
> 32. What's the difference between "char const *p" and "char * const p"?
>
> A: "char const *p" is a pointer to a constant character (you can't
> change the character); "char * const p" is a constant pointer to a
> (variable) character (i.e. you can't change the pointer). (Read
> these "inside out" to understand them. See question 69.)
==========
Old C (and ANSI C, in the absence of prototypes)
silently promotes floats to doubles when passing them as arguments,
< and makes a corresponding silent change to formal parameter
< declarations, so the old-style definition actually says that func
< takes a double.
---
> as arguments, and arranges that doubles being passed are coerced
> back to floats if the formal parameters are declared that way.
==========
(In this case, it would be clearest to change the old-style
< definition to use double as well).
---
> definition to use double as well, as long as the address of that
> parameter is not taken.)
==========
> 36. What was noalias and what ever happened to it?
>
> A: noalias was another type qualifier, in the same syntactic class as
> const and volatile, which was intended to assert that the object
> pointed to was not also pointed to ("aliased") by other pointers.
> The primary application, which is an important one, would have been
> for the formal parameters of subroutines designed to perform
> computations on large arrays. A compiler can not usually take
> advantage of vectorization or other parallelization hardware (on
> supercomputers which have it) unless it can ensure that the source
> and destination arrays do not overlap.
>
> The noalias keyword was not backed up by any "prior art," and it
> was introduced late in the review and approval process. It was
> phenomenally difficult to define precisely and explain coherently,
> and sparked widespread, acrimonious debate, including a scathing
> pan by Dennis Ritchie. It had far-ranging implications,
> particularly on several standard library interfaces, for which easy
> fixes were not readily apparent.
>
> Because of the criticism and the difficulty of defining noalias
> well, the Committee wisely declined to adopt it, in spite of its
> superficial attractions. (When writing a standard, features cannot
> be introduced halfway; their full integration, and all
> implications, must be understood.) The need for a mechanism to
> support parallel implementation of non-overlapping operations
> remains unfilled (although the C Numerical Extensions Working Group
> is examining the problem).
>
> References: ANSI Sec. 3.9.6 .
>
> 37. What are #pragmas and what are they good for?
>
> A: The #pragma directive (based on a similar feature in Ada, of all
> things) provides a single, well-defined "escape hatch" which can be
> used for all sorts of implementation-specific controls and
> extensions: source listing control, structure packing, warning
> suppression (like the old lint /* NOTREACHED */ comments), etc.
>
> References: ANSI Sec. 3.8.6 .
==========
If all of the statements in the intended macro are simple
< expressions, with no declarations, another technique is to separate
< them with commas and surround them with parentheses.
---
> expressions, with no declarations, conditionals, or loops, another
> technique is to write a single, parenthesized expression using one
> or more comma operators. (This technique also allows a value to be
> "returned.")
==========
34. How can I write a function that takes a variable number of
arguments?
< A: Use varargs or stdarg.
---
> A: Use the <stdarg.h> header (or, if you must, the older <varargs.h>).
==========
If you know how to access arguments "by hand," but have access to neither
< <stdarg.h> nor <varargs.h>, you could as easily implement one of
< them yourself, leaving your code portable.)
---
> <stdarg.h> nor <varargs.h>, you could as easily implement
> <stdarg.h> yourself, leaving your code portable.)
==========
< To use varargs, instead of stdarg, change the function header to:
---
> To use the older <varargs.h> package, instead of <stdarg.h>, change
> the function header to:
==========
That the "other half," better error detection, was deferred to lint,
was a fairly deliberate decision on the part of the earliest Unix C
compiler authors, but is inexcusable (in the absence of a supplied,
< consistent lint) in a modern compiler.
---
> supplied, consistent lint, or equivalent error checking) in a
> modern compiler.
==========
> The System V release 4 lint is ANSI-compatible, and is available
> separately (bundled with other C tools) from Unix Support Labs (a
> subsidiary of AT&T), or from System V resellers.
==========
42. Don't ANSI function prototypes render lint obsolete?
< A: No. First of all, prototypes work well only if the programmer works
---
> A: Not really. First of all, prototypes work well only if the
==========
A: Again, the problem is that space for the concatenated result is not
< properly allocated. C does not provide a true string type. C
< programmers use char *'s for strings, but must always keep
< allocation in mind. The compiler will only allocate memory for
< objects explicitly mentioned in the source code (in the case of
< "strings," this includes character arrays and string literals).
---
> properly allocated. C does not provide an automatically-managed
> string type. C compilers only allocate memory for objects
> explicitly mentioned in the source code (in the case of "strings,"
==========
< The simple strcat example could be fixed with something like
---
> strcat performs no allocation; the second string is appended to the
> first one, in place. Therefore, one fix would be to declare the
> first string as an array with sufficient space:
==========
< Note, however, that strcat appends the string pointed to by its
< second argument to that pointed to by the first, and merely returns
< its first argument, so the s3 variable is superfluous.
---
> Since strcat returns its first argument, the s3 variable is
> superfluous.
==========
> 55. How does free() know how many bytes to free?
>
> A: The malloc/free package remembers the size of each block it
> allocates and returns, so it is not necessary to remind it of the
> size when freeing.
>
> 56. Is it legal to pass a null pointer as the first argument to
> realloc()? Why would you want to?
>
> A: ANSI C sanctions this usage (and the related realloc(..., 0), which
> frees), but several earlier implementations do not support it, so
> it is not widely portable. Passing an initially-null pointer to
> realloc can make it easy to write a self-starting incremental
> allocation algorithm.
>
> References: ANSI Sec. 4.10.3.4 .
>
> 57. What is the difference between calloc and malloc? Is it safe to
> use calloc's zero-fill guarantee for pointer and floating-point
> values? Does free work on memory allocated with calloc, or do you
> need a cfree?
>
> A: calloc(m, n) is essentially equivalent to
>
> p = malloc(m * n);
> memset(p, 0, m * n);
>
> The zero fill is all-bits-zero, and does not therefore guarantee
> useful zero values for pointers (see questions 1-16) or floating-
> point values. free can (and should) be used to free the memory
> allocated by calloc.
>
> References: ANSI Secs. 4.10.3 to 4.10.3.2 .
==========
Structures are typically returned from functions in a location
< pointed to by an extra, "hidden" argument to the function. Older
---
> pointed to by an extra, compiler-supplied "hidden" argument to the
==========
A: A missing semicolon causes the compiler to believe that main returns
a struct list. (The connection is hard to see because of the
< intervening comment.) When struct-valued functions are implemented
< by adding a hidden return pointer, the generated code tries to store
< a struct with respect to a pointer which was not actually passed (in
< this case, by the C start-up code). Attempting to store a structure
< into memory pointed to by the argc or argv value on the stack (where
< the compiler expected to find the hidden return pointer) causes the
< core dump.
---
> the intervening comment.) Since struct-valued functions are
> usually implemented by adding a hidden return pointer, the
> generated code for main() actually expects three arguments,
> although only two were passed (in this case, by the C start-up
> code). See also question 103.
==========
53. How can I determine the byte offset of a field within a structure?
A: ANSI C defines the offsetof macro, which should be used if
< available. If you don't have it, a suggested implementation is
---
> available; see <stddef.h>. If you don't have it, a suggested
==========
> 66. How do you decide which integer type to use?
>
> A: If you might need large values (above 32767 or below -32767), use
> long. If space is very important (there are large arrays or many
> structures), use short. Otherwise, use int. If well-defined
> overflow characteristics are important and/or sign is not, use
> unsigned.
>
> Similar arguments operate when deciding between float and double.
> Exceptions apply if the address of a variable is taken and must
> have a particular type.
>
> In general, don't try to use char or unsigned char as a "tiny" int
> type; doing so is often more trouble than it's worth.
==========
< Any good book on C should explain techniques for reading these
< complicated C declarations "inside out" to understand them
---
> Any good book on C should explain how to read these complicated C
> declarations "inside out" to understand them ("declaration mimics
==========
When the name of a function appears in an expression but is not
being called (i.e. is not followed by a "("), it "decays" into a
< pointer (i.e. its address is implicitly taken), analagously to the
< implicit decay of an array into a pointer to its first element.
---
> pointer (i.e. it has its address implicitly taken), much as an
> array name does.
==========
< The advantages of enums are that the numeric values are
< automatically assigned, that a debugger may be able to display the
< symbolic values when enum variables are examined, and that a
< compiler may generate nonfatal warnings when enums and ints are
< indiscriminately mixed (such mixing can still be considered bad
< style even though it is not strictly illegal).
---
> The primary advantages of enums are that the numeric values are
> automatically assigned, and that a debugger may be able to display
> the symbolic values when enum variables are examined. (A compiler
> may also generate nonfatal warnings when enums and ints are
> indiscriminately mixed, since doing so can still be considered bad
> style even though it is not strictly illegal). A disadvantage is
> that the programmer has little control over the size.
==========
66. How can my program discover the complete pathname to the executable
file from which it was invoked?
< A: Depending on the operating system, argv[0] may contain all or part
< of the pathname. (It may also contain nothing.) You may be able to
< duplicate the command language interpreter's search path logic to
< locate the executable if the name in argv[0] is incomplete.
< However, there is no guaranteed or portable solution.
---
> A: argv[0] may contain all or part of the pathname, or it may contain
> nothing. You may be able to duplicate the command language
> interpreter's search path logic to locate the executable if the
> name in argv[0] is present but incomplete. However, there is no
> guaranteed or portable solution.
==========
67. How can a process change an environment variable in its caller?
Under Unix, a process can modify its own environment (some systems
< provide setenv() or putenv() functions to do this), and the modified
< environment is passed on to any child processes, but it is _not_
---
> provide setenv() and/or putenv() functions to do this), and the
> modified environment is usually passed on to any child processes,
==========
< A: It is best to use an explicit fflush(stdout) at any point within
< your program at which output should definitely be visible. Several
---
> A: It is best to use an explicit fflush(stdout) whenever output should
> definitely be visible. Several mechanisms attempt to perform the
==========
< The position of braces is less important; we have
< chosen one of several popular styles. Pick a style
< that suits you, then use it consistently.
---
> The position of braces is less important, although
> people hold passionate beliefs. We have chosen one
> of several popular styles. Pick a style that suits
> you, then use it consistently.
>
> Reference: K&R Sec. 1.2 p. 10.
==========
> 89. What can I safely assume about the initial values of variables
> which are not explicitly initialized? If global variables start
> out as "zero," is that good enough for null pointers and floating-
> point zeroes?
>
> A: Variables (and arrays) with "static" duration (that is, those
> declared outside of functions, and those declared with the storage
> class static), are guaranteed initialized to zero, as if the
> programmer had typed "= 0". Therefore, such variables are
> initialized to the null pointer (of the correct type) if they are
> pointers, and to 0.0 if they are floating-point. This requirement
> means that compilers and linkers on machines which use nonzero
> internal representations for null pointers and/or floating-point
> zeroes cannot necessarily make use of uninitialized, 0-filled
> memory, but must emit explicit initializers for these values
> (rather as if the programmer had).
>
> Variables with "automatic" duration (i.e. local variables without
> the static storage class) start out containing garbage, unless they
> are explicitly initialized. Nothing useful can be predicted about
> the garbage.
>
> Dynamically-allocated memory obtained with malloc and realloc is
> also likely to contain garbage, and must be initialized by the
> calling program, as appropriate. Memory obtained with calloc
> contains all-bits-0, but this is not necessarily useful for pointer
> or floating-point values (see question 57).
==========
printable string. How can I perform the inverse operations of
converting a struct tm or a string into a time_t?
Converting a string to a time_t is harder, because of the wide
variety of date and time formats which should be parsed. Public-
domain routines have been written for performing this function, as
< well, but they are less likely to become standardized.
---
> well (see, for example, the file partime.c, widely distributed with
> the RCS package), but they are less likely to become standardized.
==========
The usual approach is to use anonymous ftp and/or uucp from a
< central, public-spirited site, such as uunet.uu.net. However, this
---
> central, public-spirited site, such as uunet.uu.net (192.48.96.2).
==========
> various items. The "archie" mailserver can tell you which
> anonymous ftp sites have which packages; send the mail message
> "help" to archie at quiche.cs.mcgill.ca for information.
==========
> 99. How can I make this code more efficient?
>
> A: Efficiency, though a favorite comp.lang.c topic, is not important
> nearly as often as people tend to think it is. Most of the code in
> most programs is not time-critical. When code is not time-
> critical, it is far more important that it be written clearly and
> portably than that it be written maximally efficiently. (Remember
> that computers are very, very fast, and that even "inefficient"
> code can run without apparent delay.)
>
> It is notoriously difficult to predict what the "hot spots" in a
> program will be. When efficiency is a concern, it is important to
> use profiling software to determine which parts of the program
> deserve attention. Often, actual computation time is swamped by
> peripheral tasks such as I/O and memory allocation, which can be
> sped up by using buffering and cacheing techniques.
>
> For the small fraction of code that is time-critical, it is vital
> to pick a good algorithm; it is much less important to
> "microoptimize" the coding details. Source-level optimizations
> rarely make significant improvements, and often render code opaque.
> Many of the "efficient coding tricks" which are frequently
> suggested (e.g. substituting shift operators for multiplication by
> powers of two) are performed automatically by even simpleminded
> compilers. Heavyhanded "optimization" attempts can make code so
> bulky that performance is degraded. If the performance of your
> code is so important that you are willing to invest programming
> time in source-level optimizations, you would be better served by
> buying the best optimizing compiler you can afford (compilers can
> perform optimizations that are impossible at the source level).
>
> It is not the intent here to suggest that efficiency can be
> completely ignored. Most of the time, however, by simply paying
> attention to good algorithm choices, implementing them clearly and
> obviously, and avoiding obviously inefficient blunders (i.e. shun
> O(n**3) implementations of O(n**2) algorithms), perfectly
> acceptable results can be achieved.
>
> 100. Are pointers really faster than arrays? Do function calls really
> slow things down? Is i++ faster than i = i + 1?
>
> A: Precise answers to these and many similar questions depend of course on
> the processor and compiler in use. If you simply must know, you'll
> have to time test programs carefully. (Often the differences are
> so slight that hundreds of thousands of iterations are required
> even to see them. Check the compiler's assembly language output,
> if available, to see if two purported alternatives aren't compiled
> identically.)
>
> It is "usually" faster to march through large arrays with pointers
> rather than array subscripts, but for some processors the reverse
> is true.
>
> Function calls, though obviously incrementally slower than in-line
> code, contribute so much to modularity and code clarity that there
> is rarely good reason to avoid them. (Actually, by reducing bulk,
> functions can improve performance.)
>
> Before rearranging expressions such as i = i + 1, remember that you
> are dealing with a C compiler, not a keystroke-programmable
> calculator. A good compiler will generate identical code for i++,
> i += 1, and i = i + 1. The reasons for using i++ or i += 1 over
> i = i + 1 have to do with style, not efficiency.
==========
86. My floating-point calculations are acting strangely and giving me
different answers on different machines.
programming text should cover the basics. (Beware, though, that
< subtle problems can occupy numerical analysts for years.)
---
> subtle problems can occupy numerical analysts for years.) Do make
> sure that you have #included <math.h>, and correctly declared other
> functions returning double.
==========
> 103. This program crashes before it even runs! (When single-stepping
> with a debugger, it dies before the first statement in main.)
>
> A: You probably have one or more very large (kilobyte or more) local
> arrays. Many systems have fixed-size stacks, and those which
> perform dynamic stack allocation automatically (e.g. Unix) are often
> confused when the stack tries to grow by a huge chunk all at once.
>
> It is often better to declare large arrays with static duration
> (unless of course you need a fresh set with each recursive call).
==========
Trivia questions like these aren't any more pertinent for
comp.lang.c than they are for any of the other groups they
< frequently come up in. The "jargon file" (also published as _The
< Hacker's Dictionary_) contains lots of tidbits like these, as does
---
> frequently come up in. You can find lots of information in the
> net.announce.newusers frequently-asked questions postings, the
> "jargon file" (also published as _The Hacker's Dictionary_), and
==========
91. Where can I get extra copies of this list? What about back issues?
< A: For now, just pull it off the net; it is normally posted on the
< first of each month, with an Expiration: line which should keep it
---
> A: For now, just pull it off the net; it is normally posted to
> comp.lang.c on the first of each month, with an Expiration: line
==========
> Thanks to Sudheer Apte, Joe Buehler, Raymond Chen, Christopher
> Calabrese, James Davies, Norm Diamond, Ray Dunn, Stephen M. Dunn, Bjorn
> Engsig, Ron Guilmette, Doug Gwyn, Tony Hansen, Joe Harrington, Guy
> Harris, Blair Houghton, Kirk Johnson, Andrew Koenig, John Lauro,
> Christopher Lott, Tim McDaniel, Evan Manning, Mark Moraes, Francois
> Pinard, randall at virginia, Pat Rankin, Rich Salz, Chip Salzenberg, Paul
> Sand, Doug Schmidt, Patricia Shanahan, Peter da Silva, Joshua Simons,
> Henry Spencer, Erik Talvola, Clarke Thatcher, Chris Torek, Ed Vielmetti,
> Larry Virden, Freek Wiedijk, and Dave Wolverton, who have contributed,
> directly or indirectly, to this article. Special thanks to Karl Heuer,
> and particularly to Mark Brader, who (to borrow a line from Steve
> Johnson) have goaded me beyond my inclination, and frequently beyond my
> endurance, in relentless pursuit of a better FAQ list.
==========
< This article is Copyright 1988, 1990 by Steve Summit.
---
> This article is Copyright 1988, 1990, 1991 by Steve Summit.
==========
More information about the Comp.lang.c
mailing list