Path: utzoo!utgpu!watserv1!watmath!att!att!bu.edu!rpi!zaphod.mps.ohio-state.edu!think.com!mintaka!bloom-beacon!adam!scs From: scs@adam.mit.edu (Steve Summit) Newsgroups: comp.lang.c Subject: Changes to Answers to Frequently Asked Questions (FAQ) on comp.lang.c Message-ID: <1990Nov1.050059.14201@athena.mit.edu> Date: 1 Nov 90 05:00:59 GMT Sender: daemon@athena.mit.edu (Mr Background) Reply-To: scs@adam.mit.edu (Steve Summit) Organization: Thermal Technologies, Inc. Lines: 558 This article contains the changes between the previous posting of the frequently-asked questions list (October 1) 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.) < This article, which will be reposted periodically, attempts to answer --- > This article, which is posted monthly, attempts to answer these common < some of the myths which this article attempts to debunk. Two invaluable < references, which are an excellent addition to any serious programmer's < library, are: < < The C Programming Language, by Brian W. Kernighan and Dennis M. < Ritchie. < < C: A Reference Manual, by Samuel P. Harbison and Guy L. Steele, Jr. < < Both exist in several editions. Andrew Koenig's book _C Traps and < Pitfalls_ also covers many of the difficulties frequently discussed < here. < --- > some of the myths which this article attempts to debunk. Several > noteworthy books on C are listed in this article's bibliography. < please try to answer it by referring to these or other books, or to < knowledgeable colleagues, before posing your question to the net at --- > please try to answer it by checking a few of the referenced books, or by > asking knowledgeable colleagues, before posing your question to the net < your comments to scs@adam.mit.edu and/or scs%adam.mit.edu@mit.edu; this < article's From: line may be unuseable. --- > your comments to scs@adam.mit.edu, scs%adam.mit.edu@mit.edu, and/or > mit-eddie!adam!scs; this article's From: line may be unusable. > The questions answered here are divided into several categories: > > 1. Null Pointers > 2. Arrays and Pointers > 3. Order of Evaluation > 4. ANSI C > 5. C Preprocessor > 6. Variable-Length Argument Lists > 7. Memory Allocation > 8. Structures > 9. Declarations > 10. Boolean Expressions and Variables > 11. Operating System Dependencies > 12. Stdio > 13. Miscellaneous < object. That is, the address-of operator & will never "return" a --- > object. That is, the address-of operator & will never yield a null < A null pointer is different from an uninitialized pointer. A null < pointer is known not to point to any object; an uninitialized --- > A null pointer is conceptually different from an uninitialized > pointer. A null pointer is known not to point to any object; an < null pointer is required, so it can make the distinction if --- > type of null pointer is required, so it can make the distinction if < A: Not since the early days. Attempting to push pointers into < integers, or build pointers out of integers, has always been --- > A: Not since the early days. Attempting to turn pointers into > integers, or to build pointers out of integers, has always been > 7. 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 with beginning programmers, does not buy > much. It is not needed in assignments and comparisons; see question > 2. It does not even save keystrokes. Its use suggests to the > reader that the author is shaky on the subject of null pointers, and > requires the reader to check the #definition of the macro, its > invocations, and _all_ other pointer usages much more carefully. < in a non-pointer context generates an integer zero. If the null < pointer keyword were "nil" the compiler could emit an error message < for an ambiguous usage, but since it is "0" the compiler may end up < emitting incorrect code. --- > in a non-pointer context generates an integer zero instead of an > error message, and if that uncast 0 was supposed to be a null > pointer, the code may not work. < 2. If the usage of "0" or "NULL" is in a function call, cast it to < the pointer type expected by the function being called. --- > 2. If the usage of "0" or "NULL" is an argument in a function > call, cast it to the pointer type expected by the function > being called. < pointers, which you shouldn't need to know. --- > pointers, which you shouldn't need to know. Understand questions 1, > 2, and 4, and consider 9 and 13, and you'll do fine. < arrays "turn into" pointers in expressions. That is, when an array --- > arrays "decay" into pointers in expressions. That is, when an array < expected to point to the start of an array rather than to a single < value. --- > expected to point to the start of an array rather than to some > single value. < A: Perhaps no aspect of C is more confusing than pointers, and the < confusion is compounded by statements like the one above. Saying < that arrays and pointers are "equivalent" does not by any means --- > A: Much of the confusion surrounding pointers in C can be traced to > this statement. Saying that arrays and pointers are "equivalent" < (The confusion is heightened by incorrect compilers, including some < versions of pcc and pcc-derived lint's, which incorrectly accept < assignments of multi-dimensional arrays to multi-level pointers.) --- > (The confusion is heightened by the existence of incorrect > compilers, including some versions of pcc and pcc-derived lint's, > which improperly accept assignments of multi-dimensional arrays to > multi-level pointers.) < If a function is already declared as accepting a pointer to a < pointer, an intermediate pointer would need to be used when < attempting to call it with a two-dimensional array: < < int *ip = &a[0][0]; < g(&ip); < ... < g(int **ipp) {...} < < Note that this usage is liable to be misleading (if not incorrect), < since the array has been "flattened" (its shape has been lost). --- > If a function is already declared as accepting a pointer to a > pointer, it is probably incorrect to pass a two-dimensional array > directly to it. < A: Usually, you don't want one. Think about using a pointer to one of --- > A: Usually, you don't want to. Consider using a pointer to one of the > If you really need to declare a pointer to an entire array, use > something like "int (*ap)[N];" where N is the size of the array. If > the size of the array is unknown, N can be omitted, but the > resulting type, "pointer to array of unknown size," is almost > completely useless. < resulting "ragged" array often saves space, although it may not be < contiguous in memory as a real array would be. --- > resulting "ragged" array often saves space, although it is not > necessarily contiguous in memory as a real array would be. < (In "real" code, of course, malloc's return value should be < checked.) --- > (In "real" code, of course, each return value from malloc would have > to be checked.) < You can keep the array's contents contiguous, while losing the < ability to have rows of varying and different lengths, with a bit of --- > You can keep the array's contents contiguous, while making later > reallocation of individual rows difficult, with a bit of explicit < value 4. ANSI allows compilers to reject code which contains such < ambiguous or undefined side effects. --- > value 4. > > The ANSI C standard declares that code which contains such ambiguous > or undefined side effects is not merely undefined, but illegal. > Don't even try to find out how your compiler implements such things > (contrary to the ill-advised exercises in many C textbooks); as K&R > wisely point out, "if you don't know _how_ they are done on various > machines, the innocence may help to protect you." < A: There is a special exception for those operators; each of them does < imply a sequence point (i.e. left-to-right evaluation is < guaranteed). --- > A: There is a special exception for those operators, (as well as ?: ); > each of them does imply a sequence point (i.e. left-to-right > evaluation is guaranteed). Any book on C should make this clear. < arduous process, this C standard was finally ratified as an American --- > arduous process, the committee's work was finally ratified as an < library support routines, an unprecedented effort. --- > library support routines. < The cost is approximately $50.00, plus $6.00 shipping. Quantity < discounts are available. --- > The cost from ANSI is $50.00, plus $6.00 shipping. Quantity > discounts are available. (Note that ANSI derives revenues to > support its operations from the sale of printed standards, so > electronic copies are _not_ available.) < used, but it will not work for floating-point values or pointers. --- > used, but it will not work for floating-point values or pointers > (and the "obvious" supercompressed implementation for integral types > a^=b^=a^=b is, strictly speaking, illegal due to multiple side- > effects; and it will not work if the two values are the same > variable, and...). > 28. I have some old code that tries to construct identifiers with a > macro like > > #define Paste(a, b) a/**/b > > but it doesn't work any more. > > A: That comments disappeared entirely and could therefore be used for > token pasting was an undocumented feature of some early preprocessor > implementations, notably Reiser's. ANSI affirms (as did K&R) that > comments are replaced with white space. However, since the need for > pasting tokens was demonstrated and real, ANSI introduced a well- > defined token-pasting operator, ##, which can be used as follows: > > #define Paste(a, b) a##b > > Reference: ANSI Sec. 3.8.3.3 p. 91, Rationale pp. 66-7. < that an apostrophe within a contracted word looks like the beginning < of a character constant) and no newlines inside quotes. Therefore, --- > that an apostrophe within a contracted word in a comment looks like > the beginning of a character constant), and no newlines inside > 30. 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 it were > a single function-call statement. This means that the "caller" will > be supplying the final semicolon, so the macro body should not. The > macro body cannot be a simple brace-delineated compound statement, > because syntax errors would result if it were invoked (apparently as > a single statement, but with a resultant an extra semicolon) as the > if branch of an if/else statement with an explicit else clause. > > The best 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 compiler > will remove any "dead" tests or branches on the constant condition > 0, although lint may complain.) > > If all of the statements in the intended macro are simple > expressions, a simpler technique is to separate them with commas and > surround them with parentheses. > > Reference: CT&P Sec. 6.3 pp. 82-3. < extern char *malloc(); /* redundant */ < int len = 0; --- > size_t len = 0; < Using the older varargs package, rather than stdarg, requires a few < changes which are not discussed here, in the interests of brevity. --- > Under a pre-ANSI compiler, rewrite the function definition without a > prototype ("char *vstrcat(first) char *first; {"), #include > rather than , replace "#include " with > "extern char *malloc();", and use int instead of size_t. You may > also have to delete the (void) casts, and use the older varargs > package instead of stdarg. > (If you know enough about your machine's architecture, it is > possible to pick arguments off of the stack "by hand," but there is > little reason to do so, since portable mechanisms exist.) > 38. I can't get strcat to work. I tried > > #include > main() > { > char *s1 = "Hello, "; > char *s2 = "world!"; > char *s3 = strcat(s1, s2); > printf("%s\n", s3); > } > > but I got strange results. > > 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). The > programmer must arrange (explicitly) for sufficient space for the > results of run-time operations such as string concatenation, > typically by declaring arrays, or calling malloc. > > The simple strcat example could be fixed with something like > > char s1[20] = "Hello, "; > char *s2 = "world!"; > > 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. > > Reference: CT&P Sec. 3.2 p. 32. < struct is pushed on the stack, which may involve significant < overhead for large structures. It may be preferable in such cases < to pass a pointer to the structure instead. --- > struct is typically pushed on the stack, using as many words as are > required. (Pointers to functions are often chosen precisely to > avoid this overhead.) < Structures are returned from functions either in a special, static < place (which may make struct-valued functions nonreentrant) or in a < location pointed to by an extra, "hidden" argument to the function. --- > Structures are typically returned from functions in a location > pointed to by an extra, "hidden" argument to the function. Older > compilers often used a special, static location for structure > returns, although this made struct-valued function nonreentrant, > which ANSI disallows. < 45. How do I declare a pointer to a function returning a pointer to a < double? --- > 49. How do I declare an array of pointers to functions returning > pointers to functions returning pointers to characters? < A: There are at least three answers to this question: --- > A: This question can be answered in at least three ways (all assume the > hypothetical array is to have 5 elements): < 1. double *(*p)(); --- > 1. char *(*(*a[5])())(); < typedef double *pd; /* pointer to double */ < typedef pd fpd(); /* func returning ptr to double */ < typedef fpd *pfpd; /* ptr to func ret ptr to double */ < pfpd p; --- > typedef char *cp; /* pointer to char */ > typedef cp 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... */ > < cdecl> declare p as pointer to function returning pointer to double < double *(*p)(); --- > cdecl> declare a as array 5 of pointer to function returning > pointer to function returning pointer to char > char *(*(*a[5])())() > Any good book on C should explain tricks for reading these > complicated C declarations "inside out" to understand them > ("declaration mimics use"). > 51. I finally figured out the syntax for declaring pointers to > functions, but now how do I initialize one? > > A: Use something like > > extern int func(); > int (*fp)() = func; > > When the name of a function appears in an expression but is not > being called (i.e. is not followed by a "("), its address is > implicitly taken, just as is done for arrays. > > An explicit extern declaration for the function is normally needed, > since implicit external function declaration does not happen in this > case (again, because the function name is not followed by a "("). < as long as you are consistent within one program or project. --- > or use raw 1 and 0, as long as you are consistent within one program > or project. > or define "helper" macros such as > > #define Istrue(e) ((e) != 0) < _not_ necessarily 1. A good rule of thumb is to use TRUE and FALSE < (or the like) only for assignment to a Boolean variable or as the < return value from a Boolean function, never in a comparison. --- > _not_ necessarily 1. (Besides, if you believe that > "if((a == b) == TRUE)" is an improvement over "if(a == b)", why stop > there? Why not use "if(((a == b) == TRUE) == TRUE)"?) A good rule > of thumb is to use TRUE and FALSE (or the like) only for assignment > to a Boolean variable or as the return value from a Boolean > function, never in a comparison. < comp.lang.c . Several common questions are answered in frequently- < asked questions postings in the comp.unix.questions and < comp.sys.ibm.pc newsgroups. --- > comp.lang.c . Many common questions are answered in frequently- > asked questions postings in such groups as comp.unix.questions and > comp.os.msdos.programmer . Note that the answers are often not > unique even across different versions of Unix. Bear in mind when > answering system-specific questions that the answer that applies to > your system may not apply to everyone else's. < A: In general, it cannot. If the calling process is prepared to listen < explicitly for some indication that its environment should be < changed, a special-case scheme can be set up. (Under Unix, a child < process cannot directly affect its parent at all. Other operating < systems have different process environments which could < intrinsically support such communication.) --- > A: In general, it cannot. Different operating systems implement > name/value functionality similar to the Unix environment in many > different ways. Whether the "environment" can be usefully altered > by a running program, and if so, how, is entirely system-dependent. > > 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 > propagated back to the parent process. (The environment of the > parent process can only be altered if the parent is explicitly set > up to listen for some kind of change requests. The conventional > execution of the BSD "tset" program in .profile and .login files > effects such a scheme.) > 59. How can a file be shortened in-place without completely clearing or > rewriting it? > > A: BSD systems provide ftruncate(), and some MS-DOS compilers supply > chsize(), but there is no portable solution. < slightly depending on whether stdout is a terminal or not. To make < this determination, these implementations perform an operation which < fails (with ENOTTY) if stdout is not a terminal. --- > slightly if stdout is a terminal. To make the determination, these > implementations perform an operation which fails (with ENOTTY) if > stdout is not a terminal. < Or you could use fgets() to read a whole line, and then use sscanf() < or other string functions to parse the line buffer. --- > Usually the best solution is to use fgets() to read a whole line, > and then use sscanf() or other string functions to parse the line > buffer. < A: Just use sprintf. --- > A: Just use sprintf. (You'll have to allocate space for the result > somewhere anyway; see questions 37 and 38.) < Otherwise, you can try anonymous ftp and/or uucp from a central, < public-spirited site, such as uunet.uu.net, but this article cannot < track or list all of the available sites and how to access them. --- > The usual approach is to use anonymous ftp and/or uucp from a > central, public-spirited site, such as uunet.uu.net. However, this > article cannot track or list all of the available sites and how to > access them. < might want to print them. --- > might want to print them. It is hard to imagine why anyone would > want or need to place a comment inside a quoted string. It is easy > to imagine a program needing to print "/*". < A: Several grammars are floating around; keep your eyes open. There is --- > A: The definitive grammar is of course the one in the ANSI standard. > Several copies are floating around; keep your eyes open. There is < 69. Where can I get extra copies of this list? --- > 75. Where can I get extra copies of this list? What about back issues? 1469,1472c1668,1674 < A: For now, just pull it off the net; it is normally posted on about < the first of the month, with an Expiration: line which should keep < it around all month. Eventually, it may be available for anonymous < ftp, or via a mailserver. --- > 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 > around all month. Eventually, it may be available for anonymous > ftp, or via a mailserver. (Note that the size of the list is > monotonically increasing; older copies are obsolete and don't > contain anything, except the occasional typo, that the current list > doesn't.) > Bibliography > > ANSI American National Standard for Information Systems -- > Programming Language -- C, ANSI X3.159-1989. > > H&S Samuel P. Harbison and Guy L. Steele, C: A Reference Manual, > Second Edition, Prentice-Hall, 1987, ISBN 0-13-109802-0. > > PCS Mark R. Horton, Portable C Software, Prentice Hall, 1990, ISBN > 0-13-868050-7. > > K&R I Brian W. Kernighan and Dennis M. Ritchie, The C Programming > Language, Prentice Hall, 1978, ISBN 0-13-110163-3. > > K&R II Brian W. Kernighan and Dennis M. Ritchie, The C Programming > Language, Second Edition, Prentice Hall, 1988, ISBN 0-13- > 110362-8, 0-13-110370-9. > > CT&P Andrew Koenig, C Traps and Pitfalls, Addison-Wesley, 1989, ISBN > 0-201-17928-8. > > There is a more extensive bibliography in the revised Indian Hill style > guide; see question 74. < Thanks to Mark Brader, Joe Buehler, Christopher Calabrese, Stephen M. < Dunn, Tony Hansen, Guy Harris, Karl Heuer, Blair Houghton, Kirk Johnson, < Andrew Koenig, John Lauro, Christopher Lott, Rich Salz, Joshua Simons, < and Erik Talvola, who have contributed, directly or indirectly, to this < article. --- > Thanks to Mark Brader, Joe Buehler, rayc, Christopher Calabrese, Ray > Dunn, Stephen M. Dunn, Bjorn Engsig, Doug Gwyn, Tony Hansen, Joe > Harrington, Guy Harris, Karl Heuer, Blair Houghton, Kirk Johnson, Andrew > Koenig, John Lauro, Christopher Lott, Evan Manning, Mark Moraes Francois > Pinard, randall@virginia, Rich Salz, Joshua Simons, Henry Spencer, Erik > Talvola, Chris Torek, and Freek Wiedijk, who have contributed, directly > or indirectly, to this article.