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