C Usernet Article

download C Usernet Article

of 42

Transcript of C Usernet Article

  • 8/22/2019 C Usernet Article

    1/42

    A Usenet article on programming in C

    BBS: Big Blue & Cousins 604-727-7374Date: 05-24-91 (13:10) Number: 21908To: ALL Refer#: NONE (Msg #24 of 106)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #01 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARDPost: 313 of 554From: [email protected] (Steve Summit)Newsgroups: comp.lang.cSubject: Answers to Frequently Asked Questions (FAQ) on comp.lang.cDate: 1 May 91 04:03:14 GMTExpires: 1 Jun 91 04:00:00 GMTReply-To: [email protected]: Thermal Technologies, Cambridge, MALines: 2167Supersedes: X-Last-Modified: April 29, 1991

    [Last modified April 29, 1991 by scs.]

    Certain topics come up again and again on this newsgroup. They are goodquestions, and the answers may not be immediately obvious, but eachtimethey recur, much net bandwidth and reader time is wasted on repetitiveresponses, and on tedious corrections to the incorrect answers whichareinevitably posted.

    This article, which is posted monthly, attempts to answer these commonquestions definitively and succinctly, so that net discussion can moveon to more constructive topics without continual regression to firstprinciples.

    No mere newsgroup article can substitute for thoughtful perusal of afull-length language reference manual. Anyone interested enough in C tobe following this newsgroup should also be interested enough to readandstudy one or more such manuals, preferably several times. Some vendors'compiler manuals are unfortunately inadequate; a few even perpetuatesome of the myths which this article attempts to refute. Severalnoteworthy books on C are listed in this article's bibliography. Manyof the questions and answers are cross-referenced to these books, forfurther study by the interested and dedicated reader.

    If you have a question about C which is not answered in this article,please try to answer it by checking a few of the referenced books, or

    byasking knowledgeable colleagues, before posing your question to the netat large. There are many people on the net who are happy to answerquestions, but the volume of repetitive answers posted to one question,as well as the growing number of questions as the net attracts morereaders, can become oppressive. If you have questions or commentsprompted by this article, please reply by mail rather than following up-- this article is meant to decrease net traffic, not increase it.

    Besides listing frequently-asked questions, this article also

  • 8/22/2019 C Usernet Article

    2/42

    summarizesfrequently-posted answers. Even if you know all the answers, it's worthskimming through this list once in a while, so that when you see one ofits questions unwittingly posted, you won't have to waste timeanswering.

    This article is always being improved. Your input is welcomed. Sendyour comments to [email protected], scs%[email protected], and/ormit-eddie!adam!scs; this article's From: line may be unusable.

    The questions answered here are divided into several categories:

    1. Null Pointers2. Arrays and Pointers3. Order of Evaluation4. ANSI C5. C Preprocessor6. Variable-Length Argument Lists7. Lint8. Memory Allocation9. Structures10. Declarations11. Boolean Expressions and Variables12. Operating System Dependencies

    13. Stdio14. Style15. Miscellaneous (Fortran to C converters, YACC grammars, etc.)

    Herewith, some frequently-asked questions and their answers:

    --- SM 1.05 ----- I pity thee, Ye of one number system ( base A ) RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 05-24-91 (13:10) Number: 21909

    To: ALL Refer#: NONE (Msg #25 of 106)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #02 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARDSection 1. Null Pointers

    1. What is this infamous null pointer, anyway?

    A: The language definition states that for each pointer type, there isa special value -- the "null pointer" -- which is distinguishablefrom all other pointer values and which is not the address of anyobject. That is, the address-of operator & will never yield a null

    pointer, nor will a successful call to malloc. (malloc returns anull pointer when it fails, and this is a typical use of nullpointers: as a "special" pointer value with some other meaning,usually "not allocated" or "not pointing anywhere yet.")

    A null pointer is conceptually different from an uninitializedpointer. A null pointer is known not to point to any object; anuninitialized pointer might point anywhere (that is, at some randomobject, or at a garbage or unallocated address). See alsoquestions 46, 52, and 82.

  • 8/22/2019 C Usernet Article

    3/42

    As mentioned in the definition above, there is a null pointer foreach pointer type, and the internal values of null pointers fordifferent types may be different. Although programmers need notknow the internal values, the compiler must always be informedwhich type of null pointer is required, so it can make thedistinction if necessary (see below).

    References: K&R I Sec. 5.4 pp. 97-8; K&R II Sec. 5.4 p. 102; H&SSec. 5.3 p. 91; ANSI Sec. 3.2.2.3 p. 38.

    2. How do I "get" a null pointer in my programs?

    A: According to the language definition, a constant 0 in a pointercontext is converted into a null pointer at compile time. That is,in an initialization, assignment, or comparison when one side is avariable or expression of pointer type, the compiler can tell thata constant 0 on the other side requests a null pointer, andgenerate the correctly-typed null pointer value. Therefore, thefollowing fragments are perfectly legal:

    char *p = 0;if(p != 0)

    However, an argument being passed to a function is not necessarilyrecognizable as a pointer context, and the compiler may not be ableto tell that an unadorned 0 "means" a null pointer. For instance,the Unix system call "execl" takes a variable-length, null-pointer-terminated list of character pointer arguments. Togenerate a null pointer in a function call context, an explicitcast is typically required:

    execl("/bin/sh", "sh", "-c", "ls", (char *)0);

    If the (char *) cast were omitted, the compiler would not know topass a null pointer, and would pass an integer 0 instead. (Notethat many Unix manuals get this example wrong.)

    When function prototypes are in scope, argument passing becomes an"assignment context," and most casts may safely be omitted, sincethe prototype tells the compiler that a pointer is required, and ofwhich type, enabling it to correctly cast unadorned 0's. Functionprototypes cannot provide the types for variable arguments invariable-length argument lists, however, so explicit casts arestill required for those arguments. It is safest always to castnull pointer function arguments, to guard against varargs functionsor those without prototypes, to allow interim use of non-ANSIcompilers, and to demonstrate that you know what you are doing.

    Summary:

    Unadorned 0 okay: Explicit cast required:

    initialization function call,no prototype in scopeassignmentvariable argument incomparison varargs function call

    function call,

  • 8/22/2019 C Usernet Article

    4/42

    prototype in scope,fixed argument

    References: K&R I Sec. A7.7 p. 190, Sec. A7.14 p. 192; K&R IISec. A7.10 p. 207, Sec. A7.17 p. 209; H&S Sec. 4.6.3 p. 72; ANSISec. 3.2.2.3 .

    --- SM 1.05 ----- I see said he, but he didn't see... cuz he was blind. RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 05-24-91 (13:10) Number: 21910To: ALL Refer#: NONE (Msg #26 of 106)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #03 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD3. What is NULL and how is it #defined?

    A: As a matter of style, many people prefer not to have unadorned 0'sscattered throughout their programs. For this reason, thepreprocessor macro NULL is #defined (by or ),

    with value 0 (or (void *)0, about which more later). A programmerwho wishes to make explicit the distinction between 0 the integerand 0 the null pointer can then use NULL whenever a null pointer isrequired. This is a stylistic convention only; the preprocessorturns NULL back to 0 which is then recognized by the compiler (inpointer contexts) as before. In particular, a cast may still benecessary before NULL (as before 0) in a function call argument.(The table under question 2 above applies for NULL as well as 0.)

    NULL should _only_ be used for pointers; see question 8.

    References: K&R I Sec. 5.4 pp. 97-8; K&R II Sec. 5.4 p. 102; H&SSec. 13.1 p. 283; ANSI Sec. 4.1.5 p. 99, Sec. 3.2.2.3 p. 38,

    Rationale Sec. 4.1.5 p. 74.

    4. How should NULL be #defined on a machine which uses a nonzero bitpattern as the internal representation of a null pointer?

    A: Programmers should never need to know the internalrepresentation(s) of null pointers, because they are normally takencare of by the compiler. If a machine uses a nonzero bit patternfor null pointers, it is the compiler's responsibility to generateit when the programmer requests, by writing "0" or "NULL," a nullpointer. Therefore, #defining NULL as 0 on a machine for whichinternal null pointers are nonzero is as valid as on any other,because the compiler must (and can) still generate the machine's

    correct null pointers in response to unadorned 0's seen in pointercontexts.

    5. If NULL were defined as follows:

    #define NULL (char *)0

    wouldn't that make function calls which pass an uncast NULL work?

    A: Not in general. The problem is that there are machines which use

  • 8/22/2019 C Usernet Article

    5/42

    different internal representations for pointers to different typesof data. The suggested #definition would make uncast NULLarguments to functions expecting pointers to characters to workcorrectly, but pointer arguments to other types would still beproblematical, and legal constructions such as

    FILE *fp = NULL;

    could fail.

    Nevertheless, ANSI C allows the alternate

    #define NULL (void *)0

    definition for NULL. Besides helping incorrect programs to work(but only on machines with homogeneous pointers, thus questionablyvalid assistance) this definition may catch programs which use NULLincorrectly (e.g. when the ASCII NUL character was reallyintended).

    6. I use the preprocessor macro

    #define Nullptr(type) (type *)0

    to help me build null pointers of the correct type.A: This trick, though popular in some circles, does not buy much. Itis not needed in assignments and comparisons; see question 2. Itdoes not even save keystrokes. Its use suggests to the reader thatthe author is shaky on the subject of null pointers, and requiresthe reader to check the #definition of the macro, its invocations,and _all_ other pointer usages much more carefully.

    --- SM 1.05 ----- I'd rather be coding... RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FL

    BBS: Big Blue & Cousins 604-727-7374Date: 05-24-91 (13:11) Number: 21911To: ALL Refer#: NONE (Msg #27 of 106)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #04 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD7. Is the abbreviated pointer comparison "if(p)" to test for non-nullpointers valid? What if the internal representation for nullpointers is nonzero?

    A: When C requires the boolean value of an expression (in the if,

    while, for, and do statements, and with the &&, ||, !, and ?:operators), a false value is produced when the expression comparesequal to zero, and a true value otherwise. That is, whenever onewrites

    if(expr)

    where "expr" is any expression at all, the compiler essentiallyacts as if it had been written as

  • 8/22/2019 C Usernet Article

    6/42

    if(expr != 0)

    Substituting the trivial pointer expression "p" for "expr," we have

    if(p) is equivalent to if(p != 0)

    and this is a comparison context, so the compiler can tell that the(implicit) 0 is a null pointer, and use the correct value. Thereis no trickery involved here; compilers do work this way, andgenerate identical code for both statements. The internalrepresentation of a pointer does _not_ matter.

    The boolean negation operator, !, can be described as follows:

    !expr is essentially equivalent to expr?0:1

    It is left as an exercise for the reader to show that

    if(!p) is equivalent to if(p == 0)

    "Abbreviations" such as if(p), though perfectly legal, areconsidered by some to be bad style.

    See also question 68.

    References: K&R II Sec. A7.4.7 p. 204; H&S Sec. 5.3 p. 91; ANSISecs. 3.3.3.3, 3.3.9, 3.3.13, 3.3.14, 3.3.15, 3.6.4.1, and 3.6.5 .

    8. If "NULL" and "0" are equivalent, which should I use?

    A: Many programmers believe that "NULL" should be used in all pointercontexts, as a reminder that the value is to be thought of as apointer. Others feel that the confusion surrounding "NULL" and "0"is only compounded by hiding "0" behind a #definition, and preferto use unadorned "0" instead. There is no one right answer.C programmers must understand that "NULL" and "0" areinterchangeable and that an uncast "0" is perfectly acceptable in

    initialization, assignment, and comparison contexts. Any usage of"NULL" (as opposed to "0") should be considered a gentle reminderthat a pointer is involved; programmers should not depend on it(either for their own understanding or the compiler's) fordistinguishing pointer 0's from integer 0's.

    NULL should _not_ be used when another kind of 0 is required, eventhough it might work, because doing so sends the wrong stylisticmessage. (ANSI allows the #definition of NULL to be (void *)0,which will not work in non-pointer contexts.) In particular, donot use NULL when the ASCII null character (NUL) is desired.Provide your own definition

    #define NUL '\0'

    if you must.

    Reference: K&R II Sec. 5.4 p. 102.

    --- SM 1.05 ----- If it's too good to be true... Tell me about it! RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FL

  • 8/22/2019 C Usernet Article

    7/42

    BBS: Big Blue & Cousins 604-727-7374Date: 05-24-91 (13:11) Number: 21912To: ALL Refer#: NONE (Msg #28 of 106)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #05 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD9. But wouldn't it be better to use NULL (rather than 0) in case thevalue of NULL changes, perhaps on a machine with nonzero nullpointers?

    A: No. Although symbolic constants are often used in place of numbersbecause the numbers might change, this is _not_ the reason thatNULL is used in place of 0. Once again, the language guaranteesthat source-code 0's (in pointer contexts) generate null pointers.NULL is used only as a stylistic convention.

    10. I'm confused. NULL is guaranteed to be 0, but the null pointer isnot?

    A: When the term "null" or "NULL" is casually used, one of severalthings may be meant:

    1. The conceptual null pointer, the abstract language conceptdefined in question 1. It is implemented with...

    2. The internal (or run-time) representation of a null pointer,which may or may not be all-bits-0 and which may be differentfor different pointer types. The actual values should be ofconcern only to compiler writers. Authors of C programs neversee them, since they use...

    3. The source code syntax for null pointers, which is the singlecharacter "0". It is often hidden behind...

    4. The NULL macro, which is #defined to be "0" or "(void *)0".

    Finally, as a red herring, we have...

    5. The ASCII null character (NUL), which does have all bits zero,but has no relation to the null pointer except in name.

    This article always uses the phrase "null pointer" (in lower case)for sense 1, the character "0" for sense 3, and the capitalizedword "NULL" for sense 4.

    11. Why is there so much confusion surrounding null pointers? Why dothese questions come up so often?

    A: C programmers traditionally like to know more than they need to

    about the underlying machine implementation. The fact that nullpointers are represented both in source code, and internally tomost machines, as zero invites unwarranted assumptions. The use ofa preprocessor macro (NULL) suggests that the value might changelater, or on some weird machine. Finally, the distinction betweenthe several uses of the term "null" (listed above) is oftenoverlooked.

    One good way to wade out of the confusion is to imagine that C hada keyword (perhaps "nil", like Pascal) with which null pointers

  • 8/22/2019 C Usernet Article

    8/42

    were requested. The compiler could either turn "nil" into thecorrect type of null pointer, when it could determine the type fromthe source code (as it does with 0's in reality), or complain whenit could not. Now, in fact, in C the keyword for a null pointer isnot "nil" but "0", which works almost as well, except that anuncast "0" in a non-pointer context generates an integer zeroinstead of an error message, and if that uncast 0 was supposed tobe a null pointer, the code may not work.

    12. I'm still confused. I just can't understand all this null pointerstuff.

    A: Follow these two simple rules:

    1. When you want to refer to a null pointer in source code, use"0" or "NULL".

    2. If the usage of "0" or "NULL" is an argument in a functioncall, cast it to the pointer type expected by the functionbeing called.

    The rest of the discussion has to do with other people'smisunderstandings, or with the internal representation of nullpointers, which you shouldn't need to know. Understand questions

    1, 2, and 3, and consider 8 and 11, and you'll do fine.--- SM 1.05 ----- TSR = Trash System Randomly RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 05-24-91 (13:11) Number: 21913To: ALL Refer#: NONE (Msg #29 of 106)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #06 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

    13. Given all the confusion surrounding null pointers, wouldn't it beeasier simply to require them to be represented internally byzeroes?

    A: If for no other reason, doing so would be ill-advised because itwould unnecessarily constrain implementations which would otherwisenaturally represent null pointers by special, nonzero bit patterns,particularly when those values would trigger automatic hardwaretraps for invalid accesses.

    Besides, what would this requirement really accomplish? Properunderstanding of null pointers does not require knowledge of the

    internal representation, whether zero or nonzero. Assuming thatnull pointers are internally zero does not make any code easier towrite (except for a certain ill-advised usage of calloc; seequestion 52). Known-zero internal pointers would not obviate castsin function calls, because the _size_ of the pointer might still bedifferent from that of an int. (If "nil" were used to request nullpointers rather than "0," as mentioned in question 11, the urge toassume an internal zero representation would not even arise.)

    14. Seriously, have any actual machines really used nonzero null

  • 8/22/2019 C Usernet Article

    9/42

    pointers?

    A: "Certain Prime computers use a value different from all-bits-0 to encode the null pointer. Also, some largeHoneywell-Bull machines use the bit pattern 06000 to encodethe null pointer."

    -- Portable C, by H. Rabinowitz and Chaim Schaap,Prentice-Hall, 1990, page 147.

    The "certain Prime computers" were the segmented 50 series, whichused segment 07777, offset 0 for the null pointer, at least forPL/I. Later models used segment 0, offset 0 for null pointers inC, necessitating new instructions such as TCNP (Test C NullPointer), evidently as a sop to all the extant poorly-written Ccode which made incorrect assumptions.

    The Symbolics Lisp Machine, a tagged architecture, does not evenhave conventional numeric pointer nullpointer.

    Section 2. Arrays and Pointers

    15. I had the definition char x[6] in one source file, and in another I

    declared extern char *x. Why didn't it work?A: The declaration extern char *x simply does not match the actualdefinition. The type "pointer-to-type-T" is not the same as"array-of-type-T." Use extern char x[].

    References: CT&P Sec. 3.3 pp. 33-4, Sec. 4.5 pp. 64-5.

    16. But I heard that char x[] was identical to char *x.

    A: Not at all. (What you heard has to do with formal parameters tofunctions; see question 19.) Arrays are not pointers. Thedeclaration "char a[6];" requests that space for six characters be

    set aside, to be known by the name "a." That is, there is alocation named "a" at which six characters can sit. Thedeclaration "char *p;" on the other hand, requests a place whichholds a pointer. The pointer is to be kn--+a: | h | e | l | l | o |\0 |+---+---+---+---+---+---+

    +-----+ +---+---+---+---+---+---+p: | *======> | w | o | r | l | d |\0 |+-----+ +---+---+---+---+---+---+

    --- SM 1.05 ----- That's CUTTER not CDR! (Lisp Joke)

    RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 05-24-91 (13:11) Number: 21914To: ALL Refer#: NONE (Msg #30 of 106)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #07 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

  • 8/22/2019 C Usernet Article

    10/42

    17. You mean that a reference like x[3] generates different codedepending on whether x is an array or a pointer?

    A: Precisely. Referring back to the sample declarations in theprevious question, when the compiler sees the expression a[3], itemits code to start at the location "a," move three past it, andfetch the character there. When it sees the expression p[3], itemits code to start at the location "p," fetch the pointer valuethere, add three to the pointer, and finally fetch the characterpointed to. In the example above, both a[3] and p[3] happen to bethe character 'l', but the compiler gets there differently. (Seealso qu"Equivalence" refers to the following key definition:

    An lvalue of type array-of-T which appears in an expressiondecays (with three exceptions) into a pointer to its firstelement; 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 initializerfor a character array.)

    As a consequence of this definition, there is not really anydifference in the behavior of the "array subscripting" operator []

    as it applies to arrays and pointers. In an expression of the forma[i], the array reference "a" decays into a pointer, following therule above, and is then subscripted exactly as would be a pointervariable in the expression p[i]. In either case, the expressionx[i] (where x is an array or a pointer) is, by definition, exactlyequivalent to *((x)+(i)).

    References: K&R I Sec. 5.3 pp. 93-6; K&R II Sec. 5.3 p. 99; H&SSec. 5.4.1 p. 93; ANSI Sec. 3.3.2.1, Sec. 3.3.6 .

    19. Then why are array and pointer declarations interchangeable asfunction formal parameters?

    A: Since arrays decay immediately into pointers, an array is neveractually passed to a function. Therefore, any parameterdeclarations which "look like" arrays, e.g.

    f(a)char a[];

    are treated by the compiler as if they were pointers, since that iswhat the function will receive if an array is passed:

    f(a)char *a;

    This conversion holds only within function formal parametermore 218, Sec. A10.1 p. 226; H&SSec. 5.4.3 p. 96; ANSI Sec. 3.5.4.3, Sec. 3.7.1, CT&P Sec. 3.3pp. 33-4.

    20. Someone explained to me that arrays were really just constantpointers.

    A: That person did you a disservice. An array name is "constant" inthat it cannot be assigned to, but an array is _not_ a pointer, as

  • 8/22/2019 C Usernet Article

    11/42

    the discussion and pictures in question 16 should make clear.

    21. I came across some "joke" code containing the "expression"5["abcdef"] . How can this be legal C?

    A: Yes, Virginia, array subscripting is commutative in C. Thiscurious fact follows from the pointer definition of arraysubscripting, namely that a[e] is exactly equivalent to *((a)+(e)),for _any_ expression e and primary expression a, as long as one ofthem is a pointer expression and one is integral. This unsuspectedcommutativity is often mentioned in C texts as if it were somethingto be proud of, but it finds no useful application outside of theObfuscated C Contest (see question 90).

    --- SM 1.05 ----- The only GOOD Head is a DeadHead! RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 05-24-91 (13:12) Number: 21915To: ALL Refer#: NONE (Msg #31 of 106)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #08 Status: PUBLIC MSG

    Conf: C-Language-U (9) Direction: FORWARD22. My compiler complained when I passed a two-dimensional array to aroutine expecting a pointer to a pointer.

    A: The rule by which arrays decay into pointers is not appliedrecursively. An array of arrays (i.e. a two-dimensional array inC) decays into a pointer to an array, not a pointer to a pointer.Pointers to arrays can be confusing, and must be treated carefully.(The confusion is heightened by the existence of incorrectcompilers, including some versions of pcc and pcc-derived lint's,which improperly accept assignments of multi-dimensional arrays tomulti-level pointers.) If you are passing a two-dimensional array

    to a function:

    int array[YSIZE][XSIZE];f(array);

    the function's declaration should match:

    f(int a[][XSIZE]) {...}or

    f(int (*ap)[XSIZE]) {...} /* ap is a pointer to an array */

    In the first declaration, the compiler performs the usual implicit

    parameter rewriting of "array of array" to "pointer to array;" inthe second form the pointer declaration is explicit. Since thecalled function does not allocate space for the array, it does notneed to know the overall size, so the number of "rows," YSIZE, canbe 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.

    If a function is already declared as accepting a pointer to apointer, it is probably incorrect to pass a two-dimensional array

  • 8/22/2019 C Usernet Article

    12/42

    directly to it.

    23. How do I declare a pointer to an array?

    A: Usually, you don't want to. Consider using a pointer to one of thearray's elements instead. Arrays of type T decay into pointers totype T, which is convenient; subscripting or incrementing theresultant pointer accesses the individual members of the array.True pointers to arrays, when subscripted or incremented, step overentire arrays, and are generally only useful when operating onmultidimensional arrays, if at all. (See question 22 above.) Whenpeople speak casually of a pointer to an array, they usually mean apointer to its first element.

    If you really need to declare a pointer to an entire array, usesomething like "int (*ap)[N];" where N is the size of the array.(See also question 63.) If the size of the array is unknown, N canbe omitted, but the resulting type, "pointer to array of unknownsize," is useless.

    --- SM 1.05 ----- Two wrongs don't make a right... But it'ssatisfying.. RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FL

    BBS: Big Blue & Cousins 604-727-7374Date: 05-24-91 (13:12) Number: 21916To: ALL Refer#: NONE (Msg #32 of 106)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #09 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD24. How can I dynamically allocate a multidimensional array?

    A: It is usually best to allocate an array of pointers, and theninitialize each pointer to a dynamically-allocated "row." The

    resulting "ragged" array can save space, although it is notnecessarily contiguous in memory as a real array would be. Here isa two-dimensional example:

    int **array = (int **)malloc(nrows * sizeof(int *));for(i = 0; i < nrows; i++)array[i] = (int *)malloc(ncolumns * sizeof(int));

    (In "real" code, of course, malloc should be declared correctly,and each return value checked.)

    You can keep the array's contents contiguous, while making laterreallocation of individual rows difficult, with a bit of explicit

    pointer arithmetic:

    int **array = (int **)malloc(nrows * sizeof(int *));array[0] = (int *)malloc(nrows * ncolumns * sizeof(int));for(i = 1; i < nrows; i++)array[i] = array[0] + i * ncolumns;

    In either case, the elements of the dynamic array can be accessedwith normal-looking array subscripts: array[i][j].

  • 8/22/2019 C Usernet Article

    13/42

    If the double indirection implied by the above schemes is for somereason unacceptable, you can simulate a two-dimensional array witha single, dynamically-allocated one-dimensional array:

    int *array = (int *)malloc(nrows * ncolumns * sizeof(int));

    However, you must now perform subscript calculations manually,accessing the i,jth element with array[i * ncolumns + j]. (A macrocan hide the explicit calculation, but invoking it then requiresparentheses and commas which don't look exactly likemultidimensional array subscripts.)

    Section 3. Order of Evaluation

    25. Under my compiler, the code

    int i = 7;printf("%d\n", i++ * i++);

    prints 49. Regardless of the order of evaluation, shouldn't itprint 56?

    A: Although the postincrement and postdecrement operators ++ and --perform the operations after yielding the former value, many people

    misunderstand the implication of "after." It is _not_ guaranteedthat the operation is performed immediately after giving up theprevious value and before any other part of the expression isevaluated. It is merely guaranteed that the update will beperformed sometime before the expression is considered "finished"(before the next "sequence point," in ANSI C's terminology). Inthe example, the compiler chose to multiply the previous value byitself and to perform both increments afterwards.

    The behavior of code which contains ambiguous or undefined sideeffects (including ambiguous embedded assignments) has always beenundefined. (Note, too, that a compiler's choice, especially underANSI rules, for "undefined behavior" may be to refuse to compile

    the code.) Don't even try to find out how your compiler implementssuch things (contrary to the ill-advised exercises in many Ctextbooks); as K&R wisely point out, "if you don't know _how_ theyare done on various machines, that innocence may help to protectyou."

    References: K&R I Sec. 2.12 p. 50; K&R II Sec. 2.12 p. 54; ANSISec. 3.3 p. 39; CT&P Sec. 3.7 p. 47; PCS Sec. 9.5 pp. 120-1.(Ignore H&S Sec. 7.12 pp. 190-1, which is obsolete.)

    --- SM 1.05 ----- Why are they called .QWK when it takes so LONG toread?

    RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 05-24-91 (13:12) Number: 21917To: ALL Refer#: NONE (Msg #33 of 106)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #10 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

  • 8/22/2019 C Usernet Article

    14/42

    26. But what about the &&, ||, and comma operators?I see code like "if((c = getchar()) == EOF || c == '\n')" ...

    A: There is a special exception for those operators, (as well as ?: );each of them does imply a sequence point (i.e. left-to-rightevaluation is guaranteed). Any book on C should make this clear.

    References: K&R I Sec. 2.6 p. 38, Secs. A7.11-12 pp. 190-1; K&R IISec. 2.6 p. 41, Secs. A7.14-15 pp. 207-8; ANSI Secs. 3.3.13 p. 52,3.3.14 p. 52, 3.3.15 p. 53, 3.3.17 p. 55, CT&P Sec. 3.7 pp. 46-7.

    Section 4. ANSI C

    27. What is the "ANSI C Standard?"

    A: In 1983, the American National Standards Institute commissioned acommittee, X3J11, to standardize the C language. After a long,arduous process, including several widespread public reviews, thecommittee's work was finally ratified as an American NationalStandard, X3.159-1989, on December 14, 1989, and published in thespring of 1990. For the most part, ANSI C standardizes existingpractice, with a few additions from C++ (most notably functionprototypes) and support for multinational character sets (includingthe much-lambasted trigraph sequences). The ANSI C standard also

    formalizes the C run-time library support routines.The published Standard includes a "Rationale," which explains manyof its decisions, and discusses a number of subtle points,including several of those covered here. (The Rationale is "notpart of ANSI Standard X3.159-1989, but is included for informationonly.")

    The Standard has been adopted as an international standard, ISO/IEC9899:1990, although the Rationale is currently not included.

    28. How can I get a copy of the Standard?

    A: Copies are available from

    American National Standards Institute1430 BroadwayNew York, NY 10018 USA(+1) 212 642 4900

    or

    Global Engineering Documents2805 McGaw AvenueIrvine, CA 92714 USA(+1) 714 261 1455

    (800) 854 7179 (U.S. & Canada)

    The cost from ANSI is $50.00, plus $6.00 shipping. Quantitydiscounts are available. (Note that ANSI derives revenues tosupport its operations from the sale of printed standards, soelectronic copies are _not_ available.)

    The Rationale, by itself, has been printed by Silicon Press, ISBN0-929306-07-4.

  • 8/22/2019 C Usernet Article

    15/42

    29. Does anyone have a tool for converting old-style C programs to ANSIC, or for automatically generating prototypes?

    A: Two programs, protoize and unprotoize, convert back and forthbetween prototyped and "old style" function definitions anddeclarations. (These programs do _not_ handle full-blowntranslation between "Classic" C and ANSI C.) These programs existas patches to the FSF GNU C compiler, gcc. Look for the fileprotoize-1.39.0 in pub/gnu at prep.ai.mit.edu (18.71.0.38), or atseveral other FSF archive sites.

    Several prototype generators exist, many as modifications to lint.(See also question 89.)

    --- SM 1.05 ----- if 4 bits=a nybble & 8=a byte..shouldn't 16=amouthful? RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 05-27-91 (12:33) Number: 22085To: ALL Refer#: NONE (Msg #30 of 80)From: BROOKS CUTTER Read: NO

    Subj: BASICS OF C (USENET) #11 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

    30. 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'tchange the character); "char * const p" is a constant pointer to a(variable) character (i.e. you can't change the pointer). (Readthese "inside out" to understand them. See question 63.)

    31. My ANSI compiler complains about a mismatch when it sees

    extern int func(float);

    int func(x)float x;{...

    A: You have mixed the new-style prototype declaration"extern int func(float);" with the old-style definition"int func(x) float x;". Old C (and ANSI C, in the absence ofprototypes) silently promotes floats to doubles when passing themas arguments, and arranges that doubles being passed are coercedback to floats if the formal parameters are declared that way.

    The problem can be fixed either by using new-style syntaxconsistently in the definition:

    int func(float x) { ... }

    or by changing the new-style prototype declaration to match theold-style definition:

    extern int func(double);

  • 8/22/2019 C Usernet Article

    16/42

    (In this case, it would be clearest to change the old-styledefinition to use double as well, as long as the address of thatparameter is not taken.)

    Reference: ANSI Sec. 3.3.2.2 .

    32. I'm getting strange syntax errors inside code which I've #ifdeffedout.

    A: Under ANSI C, the text inside a "turned off" #if, #ifdef, or#ifndef must still consist of "valid preprocessing tokens." Thismeans that there must be no unterminated comments or quotes (noteparticularly that an apostrophe within a contracted word could looklike the beginning of a character constant), and no newlines insidequotes. Therefore, natural-language comments and pseudocode shouldalways be written between the "official" comment delimiters /* and*/. (But see also question 91.)

    References: ANSI Sec. 2.1.1.2 p. 6, Sec. 3.1 p. 19 line 37.

    33. Why does the ANSI Standard not guarantee more than six monocasecharacters of external identifier significance?

    A: The problem is older linkers which are neither under the control of

    the ANSI standard nor the C compiler developers on the systemswhich have them. The limitation is only that identifiers be_significant_ in the first six characters, not that they berestricted to six characters in length. This limitation isannoying, but certainly not unbearable, and is marked in theStandard as "obsolescent," i.e. a future revision will likely relaxit.

    This concession to current, restrictive linkers really had to bemade, no matter how vehemently some people oppose it. (TheRationale notes that its retention was "most painful.") If youdisagree, or have thought of a trick by which a compiler burdenedwith a restrictive linker could present the C programmer with the

    appearance of more significance in external identifiers, read theexcellently-worded section 3.1.2 in the X3.159 Rationale (seequestion 27), which discusses several such schemes and explains whythey could not be mandated.

    References: ANSI Sec. 3.1.2 p. 21, Sec. 3.9.1 p. 96, RationaleSec. 3.1.2 pp. 19-21.

    --- SM 1.05 ----- ( Lisp Programmers do it in parentheses ) RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FL

    BBS: Big Blue & Cousins 604-727-7374Date: 05-27-91 (12:35) Number: 22086To: ALL Refer#: NONE (Msg #31 of 80)From: BROOKS CUTTER Read: NOSubj: BASICS OF C (USENET) #12 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

    34. What was noalias and what ever happened to it?

  • 8/22/2019 C Usernet Article

    17/42

    A: noalias was another type qualifier, in the same syntactic class asconst and volatile, which was intended to assert that the objectpointed to was not also pointed to ("aliased") by other pointers.The primary application, which is an important one, would have beenfor the formal parameters of subroutines designed to performcomputations on large arrays. A compiler cannot usually takeadvantage of vectorization or other parallelization hardware (onsupercomputers which have it) unless it can ensure that the sourceand destination arrays do not overlap.

    The noalias keyword was not backed up by any "prior art," and itwas introduced late in the review and approval process. It wasphenomenally difficult to define precisely and explain coherently,and sparked widespread, acrimonious debate. It had far-rangingimplications, particularly on several standard library interfaces,for which easy fixes were not readily apparent.

    Because of the criticism and the difficulty of defining noaliaswell, the Committee wisely declined to adopt it, in spite of itssuperficial attractions. (When writing a standard, features cannotbe introduced halfway; their full integration, and allimplications, must be understood.) The need for an explicitmechanism to support parallel implementation of non-overlappingoperations remains unfilled (although the C Numerical Extensions

    Working Group is examining the problem).References: ANSI Sec. 3.9.6 .

    35. What are #pragmas and what are they good for?

    A: The #pragma directive provides a single, well-defined "escapehatch" which can be used for all sorts of implementation-specificcontrols and extensions: source listing control, structure packing,warning suppression (like the old lint /* NOTREACHED */ comments),etc.

    References: ANSI Sec. 3.8.6 .

    Section 5. C Preprocessor

    36. How can I write a generic macro to swap two values?

    A: There is no good answer to this question. If the values areintegers, a well-known trick using exclusive-OR could perhaps beused, but it will not work for floating-point values or pointers,(and it will not work if the two values are the same variable, andthe "obvious" supercompressed implementation for integral typesa^=b^=a^=b is, strictly speaking, illegal due to multiple side-effects, and...). If the macro is intended to be used on values ofarbitrary type (the usual goal), it cannot use a temporary, since

    it does not know what type of temporary it needs, and standard Cdoes not provide a typeof operator.

    The best all-around solution is probably to forget about using amacro, unless you don't mind passing in the type as a thirdargument.

    37. I have some old code that tries to construct identifiers with amacro like

  • 8/22/2019 C Usernet Article

    18/42

    #define Paste(a, b) a/**/b

    but it doesn't work any more.

    A: That comments disappeared entirely and could therefore be used fortoken pasting was an undocumented feature of some earlypreprocessor implementations, notably Reiser's. ANSI affirms (asdid K&R) that comments are replaced with white space. However,since the need for pasting tokens was demonstrated and real, ANSIintroduced a well-defined token-pasting operator, ##, which can beused like this:

    #define Paste(a, b) a##b

    Reference: ANSI Sec. 3.8.3.3 p. 91, Rationale pp. 66-7.

    --- SM 1.05 ----- 1 + 1 = 10 RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 05-27-91 (12:36) Number: 22087To: ALL Refer#: NONE (Msg #32 of 80)

    From: BROOKS CUTTER Read: NOSubj: BASICS OF C (USENET) #13 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

    38. What's the best way to write a multi-statement cpp macro?

    A: The usual goal is to write a macro that can be invoked as if itwere a single function-call statement. This means that the"caller" will be supplying the final semicolon, so the macro bodyshould not. The macro body cannot be a simple brace-delineatedcompound statement, because syntax errors would result if it wereinvoked (apparently as a single statement, but with a resultant

    extra semicolon) as the if branch of an if/else statement with anexplicit else clause.

    The traditional solution is to use

    #define Func() do { \/* declarations */ \stmt1; \stmt2; \/* ... */ \} while(0) /* (no trailing ; ) */

    When the "caller" appends a semicolon, this expansion becomes a

    single statement regardless of context. (An optimizing compilerwill remove any "dead" tests or branches on the constant condition0, although lint may complain.)

    If all of the statements in the intended macro are simpleexpressions, with no declarations or loops, another technique is towrite a single, parenthesized expression using one or more commaoperators. (This technique also allows a value to be "returned.")

    Reference: CT&P Sec. 6.3 pp. 82-3.

  • 8/22/2019 C Usernet Article

    19/42

    39. How can I write a cpp macro which takes a variable number ofarguments?

    A: One popular trick is to define the macro with a single argument,and call it with a double set of parentheses, which appear to thepreprocessor to indicate a single argument:

    #define DEBUG(args) {printf("DEBUG: "); printf args;}

    if(n != 0) DEBUG(("n is %d\n", n));

    The obvious disadvantage is that the caller must always remember touse the extra parentheses. (It is often best to use a bona-fidefunction, which can take a variable number of arguments in a well-defined way, rather than a macro. See questions 40 and 41 below.)

    --- SM 1.05 ----- Earn cash in your spare time -- Blackmail yourfriends. RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374

    Date: 05-27-91 (12:36) Number: 22088To: ALL Refer#: NONE (Msg #33 of 80)From: BROOKS CUTTER Read: NOSubj: BASICS OF C (USENET) #14 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

    Section 6. Variable-Length Argument Lists

    40. How can I write a function that takes a variable number ofarguments?

    A: Use the header (or, if you must, the older ).

    Here is a function which concatenates an arbitrary number ofstrings into malloc'ed memory:

    #include /* for NULL, size_t */#include /* for va_ stuff */#include /* for strcat et al */#include /* for malloc */

    char *vstrcat(char *first, ...){size_t len = 0;char *retbuf;

    va_list argp;char *p;

    if(first == NULL)return NULL;

    len = strlen(first);

    va_start(argp, first);

  • 8/22/2019 C Usernet Article

    20/42

    while((p = va_arg(argp, char *)) != NULL)len += strlen(p);

    va_end(argp);

    retbuf = malloc(len + 1); /* +1 for trailing \0 */

    if(retbuf == NULL)return NULL; /* error */

    (void)strcpy(retbuf, first);

    va_start(argp, first);

    while((p = va_arg(argp, char *)) != NULL)(void)strcat(retbuf, p);

    va_end(argp);

    return retbuf;}

    Usage is something like

    char *str = vstrcat("Hello, ", "world!", (char *)NULL);Note the cast on the last argument. (Also note that the callermust free the returned, malloc'ed storage.)

    Under a pre-ANSI compiler, rewrite the function definition withouta prototype ("char *vstrcat(first) char *first; {"), includerather than , replace "#include "with "extern char *malloc();", and use int instead of size_t. Youmay also have to delete the (void) casts, and use the older varargspackage instead of stdarg. See the next question for hints.

    References: K&R II Sec. 7.3 p. 155, Sec. B7 p. 254; H&S Sec. 13.4

    pp. 286-9; ANSI Secs. 4.8 through 4.8.1.3 .

    --- SM 1.05 ----- I pity thee, Ye of one number system ( base A ) RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 05-27-91 (12:37) Number: 22089To: ALL Refer#: NONE (Msg #34 of 80)From: BROOKS CUTTER Read: NOSubj: BASICS OF C (USENET) #15 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

    41. How can I write a function that takes a format string and avariable number of arguments, like printf, and passes them toprintf to do most of the work?

    A: Use vprintf, vfprintf, or vsprintf.

    Here is an "error" routine which prints an error message, precededby the string "error: " and terminated with a newline:

  • 8/22/2019 C Usernet Article

    21/42

    #include#include

    voiderror(char *fmt, ...){va_list argp;fprintf(stderr, "error: ");va_start(argp, fmt);vfprintf(stderr, fmt, argp);va_end(argp);fprintf(stderr, "\n");}

    To use the older package, instead of , changethe function header to:

    void error(va_alist)va_dcl{char *fmt;

    change the va_start line to

    va_start(argp);

    and add the line

    fmt = va_arg(argp, char *);

    between the calls to va_start and vfprintf. (Note that there is nosemicolon after va_dcl.)

    References: K&R II Sec. 8.3 p. 174, Sec. B1.2 p. 245; H&SSec. 17.12 p. 337; ANSI Secs. 4.9.6.7, 4.9.6.8, 4.9.6.9 .

    42. How can I discover how many arguments a function was actuallycalled with?

    A: This information is not available to a portable program. Somesystems provide a nonstandard nargs() function, but its use isquestionable, since it typically returns the number of wordspushed, not the number of arguments. (Floating point values andstructures are usually passed as several words.)

    Any function which takes a variable number of arguments must beable to determine from the arguments themselves how many of themthere are. printf-like functions do this by looking for formattingspecifiers (%d and the like) in the format string (which is why

    these functions fail badly if the format string does not match theargument list). Another common technique (useful when thearguments are all of the same type) is to use a sentinel value(often 0, -1, or an appropriately-cast null pointer) at the end ofthe list (see the execl and vstrcat examples under questions 2 and40 above).

    Section 7. Lint

    43. I just typed in this program, and it's acting strangely. Can you

  • 8/22/2019 C Usernet Article

    22/42

    see anything wrong with it?

    A: Try running lint first. Many C compilers are really only half-compilers, electing not to diagnose numerous source codedifficulties which would not actively preclude code generation.

    --- SM 1.05 ----- I see said he, but he didn't see... cuz he was blind. RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 05-27-91 (12:37) Number: 22090To: ALL Refer#: NONE (Msg #35 of 80)From: BROOKS CUTTER Read: NOSubj: BASICS OF C (USENET) #16 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

    44. How can I shut off the "warning: possible pointer alignmentproblem" message lint gives me for each call to malloc?

    A: The problem is that traditional versions of lint do not know, andcannot be told, that malloc "returns a pointer to space suitably

    aligned for storage of any type of object." It is possible toprovide a pseudoimplementation of malloc, using a #define inside of#ifdef lint, which effectively shuts this warning off, but asimpleminded #definition will also suppress meaningful messagesabout truly incorrect invocations. It may be easier simply toignore the message, perhaps in an automated way with grep -v.

    45. Where can I get an ANSI-compatible lint?

    A: A product called FlexeLint is available (in "shrouded source form,"for compilation on 'most any system) from

    Gimpel Software

    3207 Hogarth LaneCollegeville, PA 19426 USA(+1) 215 584 4261

    The System V release 4 lint is ANSI-compatible, and is availableseparately (bundled with other C tools) from Unix Support Labs (asubsidiary of AT&T), or from System V resellers.

    Section 8. Memory Allocation

    46. Why doesn't this fragment work?

    char *answer;

    printf("Type something:\n");gets(answer);printf("You typed \"%s\"\n", answer);

    A: The pointer variable "answer," which is handed to the gets functionas the location into which the response should be stored, has notbeen set to point to any valid storage. That is, we cannot saywhere the pointer "answer" points. (Since local variables are notinitialized, and typically contain garbage, it is not evenguaranteed that "answer" starts out as a null pointer. See

  • 8/22/2019 C Usernet Article

    23/42

    question 82.)

    The simplest way to correct the question-asking program is to use alocal array, instead of a pointer, and let the compiler worry aboutallocation:

    #include

    char answer[100], *p;printf("Type something:\n");fgets(answer, 100, stdin);if((p = strchr(answer, '\n')) != NULL)*p = '\0';printf("You typed \"%s\"\n", answer);

    Note that this example also uses fgets instead of gets (always agood idea), so that the size of the array can be specified, so thatfgets will not overwrite the end of the array if the user types anoverly-long line. (Unfortunately for this example, fgets does notautomatically delete the trailing \n, as gets would.) It wouldalso be possible to use malloc to allocate the answer buffer,and/or to parameterize its size (#define ANSWERSIZE 100).

    ---

    SM 1.05 ----- I'd rather be coding... RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 05-27-91 (12:37) Number: 22091To: ALL Refer#: NONE (Msg #36 of 80)From: BROOKS CUTTER Read: NOSubj: BASICS OF C (USENET) #17 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

    47. I can't get strcat to work. I tried

    char *s1 = "Hello, ";char *s2 = "world!";char *s3 = strcat(s1, s2);

    but I got strange results.

    A: Again, the problem is that space for the concatenated result is notproperly allocated. C does not provide an automatically-managedstring type. C compilers only allocate memory for objectsexplicitly mentioned in the source code (in the case of "strings,"this includes character arrays and string literals). Theprogrammer must arrange (explicitly) for sufficient space for the

    results of run-time operations such as string concatenation,typically by declaring arrays, or by calling malloc.

    strcat performs no allocation; the second string is appended to thefirst one, in place. Therefore, one fix would be to declare thefirst string as an array with sufficient space:

    char s1[20] = "Hello, ";

    Since strcat returns the value of its first argument (s1, in this

  • 8/22/2019 C Usernet Article

    24/42

    case), the s3 variable is superfluous.

    Reference: CT&P Sec. 3.2 p. 32.

    48. But the man page for strcat says that it takes two char *'s asarguments. How am I supposed to know to allocate things?

    A: In general, when using pointers you _always_ have to considermemory allocation, at least to make sure that the compiler is doingit for you. If a library routine's documentation does notexplicitly mention allocation, it is usually the caller's problem.

    The Synopsis section at the top of a Unix-style man page can bemisleading. The code fragments presented there are closer to thefunction definition used by the call's implementor than theinvocation used by the caller. In particular, many routines whichaccept pointers (e.g. to structs or strings), are usually calledwith the address of some object (a struct, or an array -- seequestions 18 and 19.) Another common example is stat().

    49. You can't use dynamically-allocated memory after you free it, canyou?

    A: No. Some early man pages for malloc stated that the contents of

    freed memory was "left undisturbed;" this ill-advised guarantee wasnever universal and is not required by ANSI.

    Few programmers would use the contents of freed memorydeliberately, but it is easy to do so accidentally. Consider thefollowing (correct) code for freeing a singly-linked list:

    struct list *listp, *nextp;for(listp = base; listp != NULL; listp = nextp) {nextp = listp->next;free((char *)listp);}

    and notice what would happen if the more-obvious loop iterationexpression listp = listp->next were used, without the temporarynextp pointer.

    References: ANSI Rationale Sec. 4.10.3.2 p. 102; CT&P Sec. 7.10p. 95.

    --- SM 1.05 ----- If it's too good to be true... Tell me about it! RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374

    Date: 05-27-91 (12:38) Number: 22092To: ALL Refer#: NONE (Msg #37 of 80)From: BROOKS CUTTER Read: NOSubj: BASICS OF C (USENET) #18 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

    50. How does free() know how many bytes to free?

    A: The malloc/free package remembers the size of each block it

  • 8/22/2019 C Usernet Article

    25/42

    allocates and returns, so it is not necessary to remind it of thesize when freeing.

    51. Is it legal to pass a null pointer as the first argument torealloc()? Why would you want to?

    A: ANSI C sanctions this usage (and the related realloc(..., 0), whichfrees), but several earlier implementations do not support it, soit is not widely portable. Passing an initially-null pointer torealloc can make it easier to write a self-starting incrementalallocation algorithm.

    References: ANSI Sec. 4.10.3.4 .

    52. What is the difference between calloc and malloc? Is it safe touse calloc's zero-fill guarantee for pointer and floating-pointvalues? Does free work on memory allocated with calloc, or do youneed 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 guaranteeuseful zero values for pointers (see questions 1-14) or floating-point values. free can (and should) be used to free the memoryallocated by calloc.

    References: ANSI Secs. 4.10.3 to 4.10.3.2 .

    53. What is alloca and why is its use discouraged?

    A: alloca allocates memory which is automatically freed when thefunction which called alloca returns. That is, memory allocatedwith alloca is local to a particular function's "stack frame" orcontext.

    alloca cannot be written portably, and is difficult to implement onmachines without a stack. Its use is problematical (and theobvious implementation on a stack-based machine fails) when itsreturn value is passed directly to another function, as infgets(alloca(100), 100, stdin).

    For these reasons, alloca cannot be used in programs which must bewidely portable, no matter how useful it might be.

    Section 9. Structures

    54. I heard that structures could be assigned to variables and passed

    to and from functions, but K&R I says not.

    A: What K&R I said was that the restrictions on struct operationswould be lifted in a forthcoming version of the compiler, and infact struct assignment and passing were fully functional inRitchie's compiler even as K&R I was being published. Although afew early C compilers lacked struct assignment, all moderncompilers support it, and it is part of the ANSI C standard, sothere should be no reluctance to use it.

  • 8/22/2019 C Usernet Article

    26/42

    References: K&R I Sec. 6.2 p. 121; K&R II Sec. 6.2 p. 129; H&SSec. 5.6.2 p. 103; ANSI Secs. 3.1.2.5, 3.2.2.1, 3.3.16 .

    55. How does struct passing and returning work?

    A: When structures are passed as arguments to functions, the entirestruct is typically pushed on the stack, using as many words as arerequired. (Pointers to structures are often chosen precisely toavoid this overhead.)

    Structures are typically returned from functions in a locationpointed to by an extra, compiler-supplied "hidden" argument to thefunction. Older compilers often used a special, static locationfor structure returns, although this made struct-valued functionsnonreentrant, which ANSI C disallows.

    Reference: ANSI Sec. 2.2.3 p. 13.

    --- SM 1.05 ----- Programmers do it from the Top Down! RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374

    Date: 05-27-91 (12:38) Number: 22093To: ALL Refer#: NONE (Msg #38 of 80)From: BROOKS CUTTER Read: NOSubj: BASICS OF C (USENET) #19 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

    56. The following program works correctly, but it dumps core after itfinishes. Why?

    struct list{char *item;

    struct list *next;}

    /* Here is the main program. */

    main(argc, argv)...

    A: A missing semicolon causes the compiler to believe that mainreturns a struct list. (The connection is hard to see because ofthe intervening comment.) Since struct-valued functions areusually implemented by adding a hidden return pointer, thegenerated code for main() actually expects three arguments,

    although only two were passed (in this case, by the C start-upcode). See also question 96.

    Reference: CT&P Sec. 2.3 pp. 21-2.

    57. Why can't you compare structs?

    A: There is no reasonable way for a compiler to implement structcomparison which is consistent with C's low-level flavor. A byte-by-byte comparison could be invalidated by random bits present in

  • 8/22/2019 C Usernet Article

    27/42

    unused "holes" in the structure (such padding is used to keep thealignment of later fields correct). A field-by-field comparisonwould require unacceptable amounts of repetitive, in-line code forlarge structures.

    If you want to compare two structures, you must write your ownfunction to do so. C++ would let you arrange for the == operatorto map to your function.

    References: K&R II Sec. 6.2 p. 129; H&S Sec. 5.6.2 p. 103; ANSIRationale Sec. 3.3.9 p. 47.

    58. I came across some code that declared a structure like this:

    struct name{int namelen;char name[1];};

    and then did some tricky allocation to make the name array act likeit had several elements. Is this legal and/or portable?

    A: This technique is popular, although Dennis Ritchie has called it

    "unwarranted chumminess with the compiler." The ANSI C standardallows it only implicitly. It seems to be portable to all knownimplementations. (Compilers which check array bounds carefullymight issue warnings.)

    59. How can I determine the byte offset of a field within a structure?

    A: ANSI C defines the offsetof macro, which should be used ifavailable; see . If you don't have it, a suggestedimplementation is

    #define offsetof(type, mem) ((size_t) \((char *)&((type *) 0)->mem - (char *)((type *) 0)))

    This implementation is not 100% portable; some compilers maylegitimately refuse to accept it.

    See the next question for a usage hint.

    Reference: ANSI Sec. 4.1.5 .

    --- SM 1.05 ----- TSR = Trash System Randomly RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FL

    BBS: Big Blue & Cousins 604-727-7374Date: 05-27-91 (12:38) Number: 22094To: ALL Refer#: NONE (Msg #39 of 80)From: BROOKS CUTTER Read: NOSubj: BASICS OF C (USENET) #20 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD

    60. How can I access structure fields by name at run time?

  • 8/22/2019 C Usernet Article

    28/42

    A: Build a table of names and offsets, using the offsetof() macro.The offset of field b in struct a is

    offsetb = offsetof(struct a, b)

    If structp is a pointer to an instance of this structure, and b isan int field with offset as computed above, b's value can be setindirectly with

    *(int *)((char *)structp + offsetb) = value;

    Section 10. Declarations

    61. How do you decide which integer type to use?

    A: If you might need large values (above 32767 or below -32767), uselong. If space is very important (there are large arrays or manystructures), use short. Otherwise, use int. If well-definedoverflow characteristics are important and/or negative values arenot, use the corresponding unsigned types. (But beware mixtures ofsigned and unsigned.)

    Similar arguments apply when deciding between float and double.Exceptions apply if the address of a variable is taken and must

    have a particular type.Although char or unsigned char can be used as a "tiny" int type,doing so is often more trouble than it's worth.

    62. I can't seem to define a linked list successfully. I tried

    typedef struct{char *item;NODEPTR next;} *NODEPTR;

    but the compiler gave me error messages. Can't a struct in Ccontain a pointer to itself?

    A: Structs in C can certainly contain pointers to themselves; thediscussion and example in section 6.5 of K&R make this clear. Theproblem with this example is that the NODEPTR typedef is notcomplete when the "next" field is declared. You will have to givethe structure a tag ("struct node"), and declare the "next" fieldas "struct node *next;".

    A similar problem, with a similar solution, can arise whenattempting to declare a pair of typedef'ed mutually recursivestructures.

    References: K&R I Sec. 6.5 p. 101; K&R II Sec. 6.5 p. 139; H&SSec. 5.6.1 p. 102; ANSI Sec. 3.5.2.3 .

    63. How do I declare an array of pointers to functions returningpointers to functions returning pointers to characters?

    A: This question can be answered in at least three ways (all assumethe hypothetical array is to have 5 elements):

  • 8/22/2019 C Usernet Article

    29/42

    1. char *(*(*a[5])())();

    2. Build the declaration up in stages, using typedefs:

    typedef char *pc; /* pointer to char */typedef pc fpc(); /* function returning pointer to char *typedef fpc *pfpc; /* pointer to above */typedef pfpc fpfpc(); /* function returning... */typedef fpfpc *pfpfpc; /* pointer to... */pfpfpc a[5]; /* array of... */

    3. Use the cdecl program, which turns English into C and viceversa:

    cdecl> declare a as array 5 of pointer to function returningpointer to function returning pointer to charchar *(*(*a[5])())()

    cdecl can also explain complicated declarations, help withcasts, and indicate which set of parentheses the arguments goin (for complicated function definitions, like the above).

    Any good book on C should explain how to read these complicated Cdeclarations "inside out" to understand them ("declaration mimics

    use").Reference: H&S Sec. 5.10.1 p. 116.

    --- SM 1.05 ----- That's CUTTER not CDR! (Lisp Joke) RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 06-04-91 (13:06) Number: 22446To: ALL Refer#: NONE (Msg #16 of 60)From: BROOKS CUTTER Read: NO

    Subj: Basics of C (Usenet) #22 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD68. Isn't #defining TRUE to be 1 dangerous, since any nonzero value isconsidered "true" in C? What if a built-in boolean or relationaloperator "returns" something other than 1?

    A: It is true (sic) that any nonzero value is considered true in C,but this applies only "on input", i.e. where a boolean value isexpected. When a boolean value is generated by a built-inoperator, it is guaranteed to be 1 or 0. Therefore, the test

    if((a == b) == TRUE)

    will work as expected (as long as TRUE is 1), but it is obviouslysilly. In general, explicit tests against TRUE and FALSE areundesirable, because some library functions (notably isupper,isalpha, etc.) return, on success, a nonzero value which is _not_necessarily 1. (Besides, if you believe that"if((a == b) == TRUE)" is an improvement over "if(a == b)", whystop there? Why not use "if(((a == b) == TRUE) == TRUE)"?) A goodrule of thumb is to use TRUE and FALSE (or the like) only forassignment to a Boolean variable, or as the return value from a

  • 8/22/2019 C Usernet Article

    30/42

    Boolean function, never in a comparison.

    The preprocessor macros TRUE and FALSE (and, of course, NULL) areused for code readability, not because the underlying values mightever change. That "true" is 1 and "false" 0 is guaranteed by thelanguage. (See also question 7.)

    References: K&R I Sec. 2.7 p. 41; K&R II Sec. 2.6 p. 42,Sec. A7.4.7 p. 204, Sec. A7.9 p. 206; ANSI Secs. 3.3.3.3, 3.3.8,3.3.9, 3.3.13, 3.3.14, 3.3.15, 3.6.4.1, 3.6.5; Achilles and theTortoise.

    69. What is the difference between an enum and a series of preprocessor#defines?

    A: At the present time, there is little difference. Although manypeople might have wished otherwise, the ANSI standard says thatenumerations may be freely intermixed with integral types, withouterrors. (If such intermixing were disallowed without explicitcasts, judicious use of enums could catch certain programmingerrors.)

    The primary advantages of enums are that the numeric values areautomatically assigned, and that a debugger may be able to display

    the symbolic values when enum variables are examined. (A compilermay also generate nonfatal warnings when enums and ints areindiscriminately mixed, since doing so can still be considered badstyle even though it is not strictly illegal). A disadvantage isthat the programmer has little control over the size (or over thosenonfatal warnings).

    References: K&R II Sec. 2.3 p. 39, Sec. A4.2 p. 196; H&S Sec. 5.5p. 100; ANSI Secs. 3.1.2.5, 3.5.2, 3.5.2.2 .

    Section 12. Operating System Dependencies

    70. How can I read a single character from the keyboard without waiting

    for a newline?

    A: Contrary to popular belief and many people's wishes, this is not aC-related question. The delivery of characters from a "keyboard"to a C program is a function of the operating system in use, andcannot be standardized by the C language. Some versions of curseshave a cbreak() function which does what you want. Under UNIX, useioctl to play with the terminal driver modes (CBREAK or RAW under"classic" versions; ICANON, c_cc[VMIN] and c_cc[VTIME] under SystemV or Posix systems). Under MS-DOS, use getch(). Under otheroperating systems, you're on your own. Beware that some operatingsystems make this sort of thing impossible, because charactercollection into input lines is done by peripheral processors not

    under direct control of the CPU running your program.

    Operating system specific questions are not appropriate forcomp.lang.c . Many common questions are answered in frequently-asked questions postings in such groups as comp.unix.questions andcomp.sys.ibm.pc.misc . Note that the answers are often not uniqueeven across different variants of a system. Bear in mind whenanswering system-specific questions that the answer that applies toyour system may not apply to everyone else's.

  • 8/22/2019 C Usernet Article

    31/42

    References: PCS Sec. 10 pp. 128-9, Sec. 10.1 pp. 130-1.

    --- SM 1.05 ----- Dum de dum de dum ... RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 06-04-91 (13:06) Number: 22447To: ALL Refer#: NONE (Msg #17 of 60)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #23 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD71. How can I find out if there are characters available for reading(and if so, how many)? Alternatively, how can I do a read thatwill not block if there are no characters available?

    A: These, too, are entirely operating-system-specific. Some versionsof curses have a nodelay() function. Depending on your system, youmay also be able to use "nonblocking I/O", or a system call named"select", or the FIONREAD ioctl, or kbhit(), or rdchk(), or theO_NDELAY option to open() or fcntl().

    72. How can my program discover the complete pathname to the executablefile from which it was invoked?

    A: argv[0] may contain all or part of the pathname, or it may containnothing. You may be able to duplicate the command languageinterpreter's search path logic to locate the executable if thename in argv[0] is present but incomplete. However, there is noguaranteed or portable solution.

    73. How can a process change an environment variable in its caller?

    A: In general, it cannot. Different operating systems implementname/value functionality similar to the Unix environment in

    different ways. Whether the "environment" can be usefully alteredby a running program, and if so, how, is system-dependent.

    Under Unix, a process can modify its own environment (some systemsprovide setenv() and/or putenv() functions to do this), and themodified environment is usually passed on to any child processes,but it is _not_ propagated back to the parent process.

    74. How can a file be shortened in-place without completely clearing orrewriting it?

    A: BSD systems provide ftruncate(), and several others supplychsize(), but there is no truly portable solution.

    Section 13. Stdio

    75. Why does errno contain ENOTTY after a call to printf?

    A: Many implementations of the stdio package adjust their behaviorslightly if stdout is a terminal. To make the determination, theseimplementations perform an operation which fails (with ENOTTY) ifstdout is not a terminal. Although the output operation goes on tocomplete successfully, errno still contains ENOTTY.

  • 8/22/2019 C Usernet Article

    32/42

    Reference: CT&P Sec. 5.4 p. 73.

    76. My program's prompts and intermediate output don't always show upon the screen, especially when I pipe the output through anotherprogram.

    A: It is best to use an explicit fflush(stdout) whenever output shoulddefinitely be visible. Several mechanisms attempt to perform thefflush for you, at the "right time," but they tend to apply onlywhen stdout is a terminal. (See question 75.)

    77. When I read from the keyboard with scanf(), it seems to hang untilI type one extra line of input.

    A: scanf() was designed for free-format input, which is seldom whatyou want when reading from the keyboard. In particular, "\n" in aformat string does not mean "expect a newline", it means "discardall whitespace".

    It is usually better to fgets() to read a whole line, and then usesscanf() or other string functions to parse the line buffer.

    78. How can I recover the file name given an open file descriptor?

    A: This problem is, in general, insoluble. Under Unix, for instance,a scan of the entire disk, (perhaps requiring special permissions)would theoretically be required, and would fail if the filedescriptor was a pipe or referred to a deleted file (and could givea misleading answer for a file with multiple links). It is best toremember the names of open files yourself (perhaps with a wrapperfunction around fopen).

    --- SM 1.05 ----- Earn cash in your spare time, Blackmail your friends RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FL

    BBS: Big Blue & Cousins 604-727-7374Date: 06-04-91 (13:07) Number: 22448To: ALL Refer#: NONE (Msg #18 of 60)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #24 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARDSection 14. Style

    79. Here's a neat trick:

    if(!strcmp(s1, s2))

    Is this good style?

    A: No. This is a classic example of C minimalism carried to anobnoxious degree. The test succeeds if the two strings are equal,but its form strongly suggests that it tests for inequality.

    A much better solution is to use a macro:

    #define Streq(s1, s2) (strcmp(s1, s2) == 0)

  • 8/22/2019 C Usernet Article

    33/42

    80. What's the best style for code layout in C?

    A: K&R, while providing the example most often copied, also supply agood excuse for avoiding it:

    The position of braces is less important, althoughpeople hold passionate beliefs. We have chosen oneof several popular styles. Pick a style that suitsyou, then use it consistently.

    It is more important that the layout chosen be consistent (withitself, and with nearby or common code) than that it be "perfect."If your coding environment (i.e. local custom or company policy)does not suggest a style, and you don't feel like inventing yourown, just copy K&R. (The tradeoffs between various indenting andbrace placement options can be exhaustively and minutely examined,but don't warrant repetition here. See also the Indian Hill StyleGuide.)

    Reference: K&R Sec. 1.2 p. 10.

    81. Where can I get the "Indian Hill Style Guide" and other codingstandards?

    A: Various documents are available for anonymous ftp from:

    Site: File or directory:

    cs.washington.edu ~ftp/pub/cstyle.tar.Z(128.95.1.4) (the updated Indian Hill guide)

    cs.toronto.edu doc/programming

    giza.cis.ohio-state.edu pub/style-guide

    Section 15. Miscellaneous

    82. What can I safely assume about the initial values of variableswhich are not explicitly initialized? If global variables startout as "zero," is that good enough for null pointers and floating-point zeroes?

    A: Variables with "static" duration (that is, those declared outsideof 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 nullpointer (of the correct type) if they are pointers, and to 0.0 ifthey are floating-point.

    Variables with "automatic" duration (i.e. local variables withoutthe static storage class) start out containing garbage, unless theyare explicitly initialized. Nothing useful can be predicted aboutthe garbage.

    Dynamically-allocated memory obtained with malloc and realloc isalso likely to contain garbage, and must be initialized by thecalling program, as appropriate. Memory obtained with calloccontains all-bits-0, but this is not necessarily useful for pointeror floating-point values (see question 52).

  • 8/22/2019 C Usernet Article

    34/42

    --- SM 1.05 ----- Even shadows have shadows. RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 06-04-91 (13:07) Number: 22449To: ALL Refer#: NONE (Msg #19 of 60)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #25 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD83. Can someone tell me how to write itoa (the inverse of atoi)?

    A: Just use sprintf. (You'll have to allocate space for the resultsomewhere anyway; see questions 46 and 47. Don't worry thatsprintf may be overkill, potentially wasting run time or codespace; it works well in practice.)

    References: K&R I Sec. 3.6 p. 60; K&R II Sec. 3.6 p. 64.

    84. I know that the library routine localtime will convert a time_tinto a broken-down struct tm, and that ctime will convert a time_t

    to a printable string. How can I perform the inverse operations ofconverting a struct tm or a string into a time_t?

    A: ANSI C specifies a library routine, mktime, which converts astruct tm to a time_t. Several public-domain versions of thisroutine are available in case your compiler does not support ityet.

    Converting a string to a time_t is harder, because of the widevariety of date and time formats which should be parsed. Public-domain routines have been written for performing this function(see, for example, the file partime.c, widely distributed with theRCS package), but they are less likely to become standardized.

    References: K&R II Sec. B10 p. 256; H&S Sec. 20.4 p. 361; ANSISec. 4.12.2.3 .

    85. How can I write data files which can be read on other machines withdifferent word size, byte order, or floating point formats?

    A: The best solution is to use text files (usually ASCII), writtenwith fprintf and read with fscanf or the like. (Similar advicealso applies to network protocols.) Be skeptical of argumentswhich imply that text files are too big, or that reading andwriting them is too slow. Not only is their efficiency frequentlyacceptable in practice, but the advantages of being able to

    manipulate them with standard tools can be overwhelming.

    If you must use a binary format, you can improve portability, andperhaps take advantage of prewritten I/O libraries, by making useof standardized formats such as Sun's XDR, OSI's ASN.1, or CCITT'sX.409 .

    86. I seem to be missing the system header file . Can someonesend me a copy?

  • 8/22/2019 C Usernet Article

    35/42

    A: Standard headers exist in part so that definitions appropriate toyour compiler, operating system, and processor can be supplied.You cannot just pick up a copy of someone else's header file andexpect it to work, unless that person is using exactly the sameenvironment. Ask your compiler vendor why the file was notprovided (or to send a replacement copy).

    87. How can I call Fortran (BASIC, Pascal, ADA, lisp) functions from C?(And vice versa?)

    A: The answer is entirely dependent on the machine and the specificcalling sequences of the various compilers in use, and may not bepossible at all. Read your compiler documentation very carefully;sometimes there is a "mixed-language programming guide," althoughthe techniques for passing arguments and ensuring correct run-timestartup are often arcane.

    --- SM 1.05 ----- Even the boldest zebra fears the hungry lion. RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 06-04-91 (13:07) Number: 22450

    To: ALL Refer#: NONE (Msg #20 of 60)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #26 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD88. Does anyone know of a program for converting Pascal (Fortran, lisp,"Old" C, ...) to C?

    A: Several public-domain programs are available:

    p2c written by Dave Gillespie, and posted to comp.sources.unixin March, 1990 (Volume 21).

    ptoc another comp.sources.unix contribution, this one written inPascal (comp.sources.unix, Volume 10, also patches in Volume13?).

    f2c jointly developed by people from Bell Labs, Bellcore, andCarnegie Mellon. To find about f2c, send the mail message"send index from f2c" to [email protected] orresearch!netlib. (It is also available via anonymous ftp onresearch.att.com, in directory dist/f2c.)

    A PL/M to C converter was posted to alt.sources in April, 1991.

    The following companies sell various translation tools and

    services:

    Cobalt Blue2940 Union Ave., Suite CSan Jose, CA 95124 USA(+1) 408 723 0474

    Promula Development Corp.3620 N. High St., Suite 301Columbus, OH 43214 USA

  • 8/22/2019 C Usernet Article

    36/42

    (+1) 614 263 5454

    Micro-Processor Services Inc92 Stone Hurst LaneDix Hills, NY 11746 USA(+1) 519 499 4461

    See also question 29.

    89. Where can I get copies of all these public-domain programs?

    A: If you have access to Usenet, see the regular postings in thecomp.sources.unix and comp.sources.misc newsgroups, which describe,in some detail, the archiving policies and how to retrieve copies.The usual approach is to use anonymous ftp and/or uucp from acentral, public-spirited site, such as uunet.uu.net (192.48.96.2).However, this article cannot track or list all of the availablearchive sites and how to access them. The comp.archives newsgroupcontains numerous announcements of anonymous ftp availability ofvarious items. The "archie" mailserver can tell you whichanonymous ftp sites have which packages; send the mail message"help" to [email protected] for information.

    90. When will the next International Obfuscated C Contest (IOCCC) be

    held? How can I get a copy of the current and previous winningentries?

    A: The contest typically runs from early March through mid-May. Toobtain a current copy of the rules, send email to:

    {pacbell,uunet,utzoo}!hoptoad!judges or [email protected]

    Contest winners are first announced at the Summer Usenix Conferencein mid-June, and posted to the net in July. Previous winners areavailable on uunet (see question 89) under the directory~/pub/ioccc.

    --- SM 1.05 ----- Every man is a volume, if you know how to read him. RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 06-04-91 (13:07) Number: 22451To: ALL Refer#: NONE (Msg #21 of 60)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #27 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD91. Why don't C comments nest? Are they legal inside quoted strings?

    A: Nested comments would cause more harm than good, mostly because ofthe possibility of accidentally leaving comments unclosed byincluding the characters "/*" within them. For this reason, it isusually better to "comment out" large sections of code, which mightcontain comments, with #ifdef or #if 0 (but see question 32).

    The character sequences /* and */ are not special within double-quoted strings, and do not therefore introduce comments, because aprogram (particularly one which is generating C code as output)

  • 8/22/2019 C Usernet Article

    37/42

    might want to print them.

    Reference: ANSI Rationale Sec. 3.1.9 p. 33.

    92. How can I make this code more efficient?

    A: Efficiency, though a favorite comp.lang.c topic, is not importantnearly as often as people tend to think it is. Most of the code inmost programs is not time-critical. When code is not time-critical, it is far more important that it be written clearly andportably than that it be written maximally efficiently. (Rememberthat 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 aprogram will be. When efficiency is a concern, it is important touse profiling software to determine which parts of the programdeserve attention. Often, actual computation time is swamped byperipheral tasks such as I/O and memory allocation, which can besped up by using buffering and cacheing techniques.

    For the small fraction of code that is time-critical, it is vitalto pick a good algorithm; it is less important to "microoptimize"the coding details. Many of the "efficient coding tricks" which

    are frequently suggested (e.g. substituting shift operators formultiplication by powers of two) are performed automatically byeven simpleminded compilers. Heavyhanded "optimization" attemptscan make code so bulky that performance is degraded.

    For more discussion of efficiency tradeoffs, as well as good adviceon how to increase efficiency when it is important, see chapter 7of Kernighan and Plaugher's The Elements of Programming Style, andJon Bentley's Writing Efficient Programs.

    93. Are pointers really faster than arrays? Do function calls reallyslow things down? Is ++i faster than i = i + 1?

    A: Precise answers to these and many similar questions depend ofcourse on the processor and compiler in use. If you simply mustknow, you'll have to time test programs carefully. (Often thedifferences are so slight that hundreds of thousands of iterationsare required even to see them. Check the compiler's assemblylanguage output, if available, to see if two purported alternativesaren't compiled identically.)

    It is "usually" faster to march through large arrays with pointersrather than array subscripts, but for some processors the reverseis true.

    Function calls, though obviously incrementally slower than in-line

    code, contribute so much to modularity and code clarity that thereis rarely good reason to avoid them.

    Before rearranging expressions such as i = i + 1, remember that youare dealing with a C compiler, not a keystroke-programmablecalculator. A good compiler will generate identical code for ++i,i += 1, and i = i + 1. The reasons for using ++i or i += 1 overi = i + 1 have to do with style, not efficiency.

    ---

  • 8/22/2019 C Usernet Article

    38/42

    SM 1.05 ----- Every purchase has its price. RNet 1.07U: U'NI-net/US: The DreamLand Express St.Petersburg FLBBS: Big Blue & Cousins 604-727-7374Date: 06-04-91 (13:07) Number: 22452To: ALL Refer#: NONE (Msg #22 of 60)From: BROOKS CUTTER Read: NOSubj: Basics of C (Usenet) #28 Status: PUBLIC MSGConf: C-Language-U (9) Direction: FORWARD94. My floating-point calculations are acting strangely and giving medifferent answers on different machines.

    A: Most digital computers use floating-point formats which provide aclose but by no means exact simulation of real number arithmetic.Among other things, the associative and distributive laws do nothold completely (i.e. order of operation may be important, repeatedaddition is not necessarily equivalent to multiplication).Underflow or cumulative precision loss is often a problem.

    Don't assume that floating-point results will be exact, andespecially don't assume that floating-point values can be comparedfor equality. (Don't throw haphazard "fuzz factors" in, either.)

    These problems are no worse for C than they are for any othercomputer language. Floating-point semantics are usually defined as"however the processor does them;" otherwise a compiler for amachine without the "right" model would have to do prohibitivelyexpensive emulations.

    This article cannot begin to list the pitfalls associated with, andworkarounds appropriate for, floating-point work. A goodprogramming text should cover the basics. Do make sure that youhave #included , and correctly declared other functionsreturning double.

    References: K&P Sec. 6 pp. 115-8.

    95. I'm having trouble with a Turbo C program which crashes and sayssomething like "floating point not loaded."

    A: Some compilers for small machines, including Turbo C (and Ritchie'soriginal PDP-11 compiler), leave out floating point support if itlooks like it will not be needed. In particular, the non-floating-point versions of printf and scanf save space by notincluding code to handle %e, %f, and %g. It happens that Turbo C'sheuristics for determining whether the program uses floating pointare occasionally insufficient, and the programmer must sometimesinsert a dummy explicit floating-point call to force loading of

    floating-point support.

    In general, questions about a particular compiler are inappropriatefor comp.lang.c . Problems with PC compilers, for instance, willfind a more receptive audience in a PC newsgroup (e.g.comp.os.msdos.programmer).

    96. This program crashes before it even runs! (When single-steppingwith a debugger, it dies before the first statement in main.)

  • 8/22/2019 C Usernet Article

    39/42

    A: You probably have one or more very large (kilobyte or more) lo