the top 10 ways to get screwed by the

Upload: ivyzengoh

Post on 10-Apr-2018

219 views

Category:

Documents


0 download

TRANSCRIPT

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    1/56

    The Top 10 Ways to get screwed by the "C" programming language

    Last modified June 11, 2003.To get on this list, a bug has to be able to cause at least half a day of futile headscratching, and has to be aggravated by the poor design of the "C" language. In theinterests of equal time, and to see how the world has progressed in the 20-odd years since

    "C" escaped from its spawning ground, see my Top 10 Ways to be Screwed by the Javaprogramming language, and for more general ways to wase a lot of time due to badsoftware, try my Adventures in Hellpage.A better language would allow fallible programmers to be more productive. Infallibleprogrammers, of the type unix' and "C" designers anticipated, need read no further. Infairness, I have to admit that the writers of compilers have improved on the situation inrecent years, by detecting and warning about potentially bad code in many cases.Non-terminated comment, "accidentally" terminated by some subsequent comment, withthe code in between swallowed.

    a=b; /* this is a bugc=d; /* c=d will never happen */

    Accidental assignment/Accidental Booleansif(a=b) c; /* a always equals b, but c will be executed if b!=0 */Depending on your viewpoint, the bug in the language is that the assignment operator istoo easy to confuse with the equality operator; or maybe the bug is that C doesn't muchcare what constitutes a boolean expression: (a=b) is not a boolean expression! (but Cdoesn't care).Closely related to this lack of rigor in booleans, consider this construction:

    if( 0 < a < 5) c; /* this "boolean" is always true! */Always true because (0

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    2/56

    now, F1. and F2 disagree about the fundamental attributes of structure "foo". If they talkto each other, You Lose!

    Phantom returned valuesSuppose you write this

    int foo (a){ if (a) return(1); } /* buggy, because sometimes no value is returned */Generally speaking, C compilers, and C runtimes either can't or don't tell you there isanything wrong. What actually happens depends on the particular C compiler and whattrash happened to be left lying around wherever the caller is going to look for thereturned value. Depending on how unlucky you are, the program may even appear towork for a while.Now, imagine the havoc that can ensue if "foo" was thought to return a pointer!

    Unpredictable struct constructionConsider this bit packing struct:

    struct eeh_type{uint16 size: 10; /* 10 bits */uint16 code: 6; /* 6 bits */

    };Depending on which C compiler, and which "endian" flavor of machine you are on, thismight actually be implemented as

    or as

    So what matters? If you are trying to match bits in a real world file, everything!Indefinite order of evaluation (contributed by [email protected])

    foo(pointer->member, pointer = &buffer[0]);Works with gcc (and other compilers I used until I tried acc) and does not with acc. Thereason is that gcc evaluates function arguments from left to right, while acc evaluatesarguments from right to left.K&R and ANSI/ISO C specifications do not define the order of evaluation for functionarguments. It can be left-to-right, right-to-left or anything else and is "unspecified". Thusany code which relies on this order of evaluation is doomed to be non portable, evenacross compilers on the same platform.This isn't an entirely non controversial point of view. Read the supplementary dialog onthe subject.

    Easily changed block scope (Suggested by Marcel van der Peijl)

    if( ... )foo();

    elsebar();

    which, when adding debugging statements, becomes

    2

    http://www.andromeda.com/people/ddyer/top-ten-supplement.html#evaluation-orderhttp://www.andromeda.com/people/ddyer/top-ten-supplement.html#evaluation-order
  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    3/56

    if( ... )foo(); /* the importance of this semicolon can't be overstated */

    elseprintf( "Calling bar()" ); /* oops! the else stops here */bar(); /* oops! bar is always executed */

    There is a large class of similar errors, involving misplaced semicolons and brackets.

    Permissive compilation (suggested by James M. Stern)I once modified some code that called a function via a macro:

    CALLIT(functionName,(arg1,arg2,arg3));CALLIT did more than just call the function. I didn't want to do the extra stuff so Iremoved the macro invocation, yielding:

    functionName,(arg1,arg2,arg3);Oops. This does not call the function. It's a comma expression that:Evaluates and then discards the address of functionName

    Evaluates the parenthesized comma expression (arg1,arg2,arg3)C's motto: who cares what it means? I just compile it! My own favorite in this vein isthis:

    switch (a) {int var = 1; /* This initialization typically does not happen. */

    /* The compiler doesn't complain, but it sure screws things up! */case A: ...case B: ...}

    Still not convinced? Try this one (suggested by Mark Scarbrough ):#define DEVICE_COUNT 4uint8 *szDevNames[DEVICE_COUNT] = {

    "SelectSet 5000","SelectSet 7000"}; /* table has two entries of junk */

    Unsafe returned values (suggested by Bill Davis )char *f() {

    char result[80];sprintf(result,"anything will do");return(result); /* Oops! result is allocated on the stack. */

    }int g(){

    char *p;p = f();printf("f() returns: %s\n",p);

    }The "wonderful" thing about this bug is that it sometimes seems to be a correct program;As long as nothing has reused the particular piece of stack occupied by result.

    Undefined order of side effects. (suggested by [email protected] and others)

    3

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    4/56

    Even within a single expression, even with only strictly manifest side effects, C doesn'tdefine the order of the side effects. Therefore, depending on your compiler, I/++I mightbe either 0 or 1. Try this:#include

    int foo(int n) {printf("Foo got %d\n", n); return(0);}

    int bar(int n) {printf("Bar got %d\n", n); return(0);}

    int main(int argc, char *argv[]){

    int m = 0;int (*(fun_array[3]))();

    int i = 1;int ii = i/++i;

    printf("\ni/++i = %d, ",ii);

    fun_array[1] = foo; fun_array[2] = bar;

    (fun_array[++m])(++m);}

    Prints either i/++i = 1 or i/++i=0;Prints either "Foo got 2", or "Bar got 2"

    Uninitialized local variablesActually, this bug is so well known, it didn't even make the list! That doesn't make it lessdeadly when it strikes. Consider the simplest case:void foo(a){ int b;

    if(b) {/* bug! b is not initialized! */ }}and in truth, modern compilers will usually flag an error as blatant as the above.However, you just have to be a little more clever to outsmart the compiler. Consider:void foo(int a){ BYTE *B;

    if(a) B=Malloc(a);if(B) { /* BUG! B may or may not be initialized */ *b=a; }

    }Cluttered compile time environmentThe compile-time environment of a typical compilation is cluttered with hundreds (orthousands!) of things that you typically have little or no awareness of. These thingssometimes have dangerously common names, leading to accidents that can be virtuallyimpossible to spot.

    4

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    5/56

    #include #define BUFFSIZE 2048long foo[BUFSIZ]; //note spelling of BUFSIZ != BUFFSIZEThis compiles without error, but will fail in predictably awful and mysterious ways,because BUFSIZ is a symbol defined by stdio.h. A typo/braino like this can be virtually

    impossible to find if the distance between the the #define and the error is greater than inthis trivial example.

    Underconstrained fundamental typesI've been seriously burned because different compilers, or even different options of thesame compiler, define the fundamental type intas either 16 or 32 bits.. In the same vein,name any other language in which boolean might be defined or undefined, or might bedefined by a compiler option, a runtime pragma (yes! we have booleans!), or just aboutany way the user decided would work ok.

    Utterly unsafe arrays

    This is so obvious it didn't even make the list for the first 5 years, but C's arrays andassociated memory management are completely, utterly unsafe, and even obvious casesof error are not detected.int thisIsNuts[4]; int i;for ( i = 0; i < 10; ++i ){thisIsNuts[ i ] = 0; /* Isn't it great ? I can use elements 1-10 of a 4 element array,

    and no one cares */}

    Of course, there are infinitely many ways to do things like this in C.

    Octal numbers (suggested by Paul C. Anagnostopoulos)In C, numbers beginning with a zero are evaluated in base 8. If there are no 8's or 9's inthe numbers, then there will be no complaints from the compiler, only screams from theprogrammer when he finally discovers the nature of the problem.

    int numbers[] = { 001, // line up numbers for typographical clarity, lose big time010, // 8 not 10014 }; // 12, not 14

    Reserved for future expansion. Send email to [email protected] of volatile

    The compilation system tries to reduce code size and execution time on all machines, byoptimizing code. It is programmer responsibility to inform compilation system thatcertain code (or variable) should not be optimized. Many programmers do not understandwhen to use volatile to inform compilation system that certain code should not beoptimized or what it does. Although (no doubt) their program work, they do not exploitthe full power of the language.

    A variable should be declared volatile whenever its value can be changed by somethingbeyond the control of the program in which it appears, such as a concurrently executing

    5

    mailto:pau%3Cn%[email protected]://email%28%29/mailto:pau%3Cn%[email protected]://email%28%29/
  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    6/56

    thread. Volatile, can appear only once in a declaration with any type specifier; however,they cannot appear after the first comma in a multiple item declaration. For example, thefollowing declarations are legal/* Let T denotes some data type */typedef volatile T i;

    volatile T i;T volatile i ;And the following declaration is illegalT i, volatile vi ;Volatile qualifiers can be used to change the behavior of a type. For example,volatile int p = 3;declares and initializes an object with type volatile int whose value will be always readfrom memory.SyntaxKeyword volatile can be placed before or after the data type in the variable definition. Forexample following declaration are identical:

    Volatile T a =3;T volatile a=3;The declaration declares and initializes an objet with type volatile T whose value will bealways read from memoryPointer declarationVolatile T * ptr;T volatile * ptr;Ptr is a a pointer to a volatile T:volatile pointer to a volatile variableint volatile * volatile ptr;volatile can be applied to derived types such as an array type ,in that case, the element isqualified, not the array type. When applied to struct types entire contents of the structbecome volatile. You can apply the volatile qualifier to the individual members of thestruct. Type qualifiers are relevant only when accessing identifiers as l-values inexpressions. volatile does not affects the range of values or arithmetic properties of theobject.. To declare the item pointed to by the pointer as volatile, use a declaration of theform:volatile T *vptr;

    To declare the value of the pointer - that is, the actual address stored in the pointer - asvolatile, use a declaration of the form:T* volatile ptrv;Use of volatile

    - An object that is a memory-mapped I/O port- An object variable that is shared between multiple concurrent processes- An object that is modified by an interrupt service routine- An automatic object declared in a function that calls setjmp and whose value is-changedbetween the call to setjmp and a corresponding call to longjmp# An object that is a memory-mapped I/O port

    6

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    7/56

    an 8 bit , memory -mapped I/O port at physical address 0X15 can be declared aschar const ptr=(char*)0X15 ;*ptr access the port consider following code fragment to set the third bit of the outputport at periodic intervals*ptr = 0;

    while(*ptr){*ptr = 4 ;*ptr = 0 ;

    }the above code may be optimize as*ptr = 0while(0) {}*ptr is assigned 0 before value 4 is used ( and value of *ptr never changes ( same constantis always assigned to it)volatile keyword is used to suppress these optimization the compiler assumes that the

    value can change any time , even if no explicit code modify it to suppress all optimizationdeclare ptr asvolatile char * const ptr = (volatile char*)0x16

    this declaration say the object at which ptr points can change without notice , but that ptritself is a constant whose value never change# An object that is shared between multiple concurrent processesif two threads/tasks concurrently assign distinct values to the same shared non-volatilevariable, a subsequent use of that variable may obtain a value that is not equal to either ofthe assigned values, but some implementation-dependent mixture of the two values. so aglobal variable references by multiple thread programmers must declare shared variableas volatile.#include#includevolatile int num ;void* foo(){while(1) {

    ++num ;sleep(1000);}

    }

    main(){int p ;void *targ =NULL ;thread_t id ;num = 0;p = thr_create((void*)NULL , 0,foo,targ,0,&id);if(!p) printf(" can not create thread ");

    7

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    8/56

    while(1){printf("%d" , num ) ;

    }

    }the compiler may use a register to store the num variable in the main thread , so thechange to the value by the second thread are ignored . The volatile modifier is a away oftelling the compiler that no optimization applied to the variable its value be not placed inregister and value may change outside influence during evaluation

    # An automatic object declared in a function that calls setjmp and whose value is-changed between the call to setjmp and a corresponding call to longjmp

    Variables local to functions that call setjmp is most often used. When an automatic objectis declared in a function that calls setjmp, the compilation system knows that it has to

    produce code that exactly matches what the programmer wrote. Therefore, the mostrecent value for such an automatic object will always be in memory (not just in a register)and as such will be guaranteed to be up-to-date when longjmp is called. Without volatilevariable is undefined by the standard whether the result one see differs with or withoutoptimization simply reflects that fact Consider following code#includestatic jmp_buf buf ;main( ){

    volatile int b;b =3 ;if(setjmp(buf)!=0) {printf("%d ", b) ;exit(0);}b=5;longjmp(buf , 1) ;

    }volatile variable isn't affected by the optimization. So value of b is after the longjump isthe last value variable assigned. Without volatile b may or may not be restored to its lastvalue when the longjmp occurs. For clear understanding assembly listing of aboveprogram by cc compiler has been given below./*Listing1: Assembly code fragment of above program

    Produced by cc compiler when volatile is used*/

    .file "vol.c"main:

    pushl %ebp

    8

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    9/56

    movl %esp, %ebpsubl $20, %espmovl $3, -4(%ebp)pushl $bufcall _setjmp

    addl $16, %esptestl %eax, %eaxje .L18subl $8, %espmovl -4(%ebp), %eaxpushl %eaxpushl $.LC0call printf movl $0, (%esp)call exit.p2align 2

    .L18: movl $5, -4(%ebp)subl $8, %esppushl $1pushl $bufcall longjmp

    /*Listing 2:Assemply code fragment of above programproduced by cc compile witout volatile keword */

    .file "wvol.c"main:

    pushl %ebpmovl %esp, %ebpsubl $20, %esppushl $bufcall _setjmpaddl $16, %esptestl %eax, %eaxje .L18subl $8, %esppushl $3pushl $.LC0call printf movl $0, (%esp)call exit.p2align 2

    .L18:subl $8, %esppushl $1

    9

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    10/56

    pushl $bufcall longjmp

    /listing 3: difference between listing 1 and listing 3 ***/

    < .file "vol.c"---> .file "wvol.c"< movl $3, -4(%ebp)< movl -4(%ebp), %eax< pushl %eax> pushl $3< movl $5, -4(%ebp) / * store in stack */

    From above listing 3 it is clear that when you use setjmp and longjmp, the only automaticvariables guaranteed to remain valid are those declared volatile.

    # An object modified by an interrupt service routineInterrupt service routines often set variables that are tested in main line code. Oneproblem that arises as soon as you use interrupt is that interrupt routines need tocommunicate with rest of the code .A interrupt may update a variable num that is used inmain line of code .An incorrect implementation of this might be:static lon int num ;void interrupt update(void){++num ;}main(){long val ;val = num ;while(val !=num)val = num ;rturn val ;}When compilation system execute while statement, the optimizer in compiler may noticethat it read the value num once already and that value is still in the register. Instead of rereading the value from memory, compiler may produce code to use the (possibly messedup) value in the register defeating purpose of original C program. Some compiler mayoptimize entire while loop assuming that since the value of num was just assigned to val ,the two must be equal and condition in while statement will therefore always be false .Toavoid this ,you have to declare num to be volatile that warns compilers that certainvariables may change because of interrupt routines.static volatile long int num ;With volatile keyword in the declaration the compiler knows that the value of num mustb read from memory every time it is referenced.

    10

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    11/56

    Problems discussed:--------------------------------------------------------------------------------------------------------------------1. Print out the non-existent alphabets in a message of length, say 80 characters.

    Soln:i) Assume case-insensitivity. Take a int array of size 26 - initializeii) Keep changing value for positions in the array corresponding to the alphabetsiii) Print out the alphabets corresponding to the unchanged positions in the array

    --------------------------------------------------------------------------------------------------------------------2. To find whether a singly-linked list is circular or notSoln:

    i) Take 2 pointers - PT1 & PT2 - start from any current position where both pointersare pointing

    ii) Within a loop, PT1 will point to the "NEXT" location. PT2 will correspond to the

    "NEXT + 2" location.iii) Keep incrementing the loop until -a. Any of them points to NULL

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    12/56

    --------------------------------------------------------------------------------------------------------------------Static VARIABLE--------------------------------------------------------------------------------------------------------------------

    In C:i) The value of this variable remains the same within it's scope, ie, if a main function isusing a local static variable, then after a function call is made within main, the previousvalue of the static variable is available to the main - even if the value might have beenchanged within the called function.ii) In case the static variable is global to all the functions within the file, then the valueof the static variable changed within a called function is available to the calling function.iii) In case there are any static variables within a file, then globals with the same namefrom different files will give a problem while LINKINGIn C++:

    i) Same rules as in Cii)

    --------------------------------------------------------------------------------------------------------------------Static FUNCTION--------------------------------------------------------------------------------------------------------------------In C:i) Such functions within a file are "PRIVATE" to that file for access.In C++:i) Refer to C++ "CONSTANT" static rules.--------------------------------------------------------------------------------------------------------------------Static STRUCTURE--------------------------------------------------------------------------------------------------------------------In C:i) By default, variables within a static structure type are also staticIn C++:i) Same as in C--------------------------------------------------------------------------------------------------------------------Storage areas in Memory for different types of variables:----------------------------------------------------------------Variable Type Storage Space

    12

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    13/56

    ----------------------------------------------------------------Register --> Within processor RegistersAutomatic &Local --> Within stackExtern --> Permanent storage space

    Dynamic --> Heap areaVolatile --> (Don't know)----------------------------------------------------------------

    Variables which have no addresses of their own:1. Register variables2. (Don't know)Open issues:1. Volatile

    2. Constant3. Static ClassesFrom: Vivek Atreya [[email protected]]Sent: Wednesday, September 03, 2003 10:10 AMTo: Suganya; Yogesh. Datarkar; Ritesh. ParikhCc: Ravindra; [email protected]; Gurpreet KhandpurSubject: Latest C Faq - Must read

    Selected message from thread

    From: Steve Summit ([email protected])Subject: comp.lang.c Answers (Abridged) to Frequently Asked Questions (FAQ)

    View this article onlyNewsgroups: comp.lang.c, comp.lang.c.moderated, comp.answers, news.answersDate: 2003-09-01 03:00:55 PST

    Archive-name: C-faq/abridgedComp-lang-c-archive-name: C-FAQ-list.abridgedURL: http://www.eskimo.com/~scs/C-faq/top.html

    [Last modified February 7, 1999 by scs.]

    This article is Copyright 1990-1999 by Steve Summit. Content from thebook _C Programming FAQs: Frequently Asked Questions_ is made availablehere by permission of the author and the publisher as a service to thecommunity. It is intended to complement the use of the published text

    13

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    14/56

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    15/56

    pointers to functions returning pointers to characters?

    A: char *(*(*a[N])())();Using a chain of typedefs, or the cdecl program, makes thesedeclarations easier.

    1.22: How can I declare a function that returns a pointer to afunction of its own type?

    A: You can't quite do it directly. Use a cast, or wrap a structaround the pointer and return that.

    1.25: My compiler is complaining about an invalid redeclaration of afunction, but I only define it once.

    A: Calling an undeclared function declares it implicitly as

    returning int.

    1.25b: What's the right declaration for main()?

    A: See questions 11.12a to 11.15.

    1.30: What am I allowed to assume about the initial valuesof variables which are not explicitly initialized?

    A: Uninitialized variables with "static" duration start out as 0,as if the programmer had initialized them. Variables with"automatic" duration, and dynamically-allocated memory, startout containing garbage (with the exception of calloc).

    1.31: Why can't I initialize a local array with a string?

    A: Perhaps you have a pre-ANSI compiler.

    1.31b: What's wrong with "char *p = malloc(10);" ?

    A: Function calls are not allowed in initializers for global orstatic variables.

    1.32: What is the difference between char a[] = "string"; andchar *p = "string"; ?

    A: The first declares an initialized and modifiable array; thesecond declares a pointer initialized to a not-necessarily-modifiable constant string.

    15

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    16/56

    1.34: How do I initialize a pointer to a function?

    A: Use something like "extern int func(); int (*fp)() = func;" .

    Section 2. Structures, Unions, and Enumerations

    2.1: What's the difference between struct x1 { ... }; andtypedef struct { ... } x2; ?

    A: The first structure is named by a tag, the second by a typedefname.

    2.2: Why doesn't "struct x { ... }; x thestruct;" work?

    A: C is not C++.

    2.3: Can a structure contain a pointer to itself?

    A: See question 1.14.

    2.4: What's the best way of implementing opaque (abstract) data typesin C?

    A: One good way is to use structure pointers which point tostructure types which are not publicly defined.

    2.6: I came across some code that declared a structure with the lastmember an array of one element, and then did some trickyallocation to make it act like the array had several elements.Is this legal or portable?

    A: An official interpretation has deemed that it is not strictlyconforming with the C Standard.

    2.7: I heard that structures could be assigned to variables andpassed to and from functions, but K&R1 says not.

    A: These operations are supported by all modern compilers.

    2.8: Is there a way to compare structures automatically?

    A: No.

    2.10: Can I pass constant values to functions which accept structurearguments?

    16

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    17/56

    A: Not yet. As of this writing, C has no way of generatinganonymous structure values.

    2.11: How can I read/write structures from/to data files?

    A: It is relatively straightforward to use fread and fwrite.

    2.12: How can I turn off structure padding?

    A: There is no standard method.

    2.13: Why does sizeof report a larger size than I expect for astructure type?

    A: The alignment of arrays of structures must be preserved.

    2.14: How can I determine the byte offset of a field within astructure?

    A: ANSI C defines the offsetof() macro, which should be used ifavailable.

    2.15: How can I access structure fields by name at run time?

    A: Build a table of names and offsets, using the offsetof() macro.

    2.18: I have a program which works correctly, but dumps core after itfinishes. Why?

    A: Check to see if a structure type declaration just before main()is missing its trailing semicolon, causing main() to be declaredas returning a structure. See also questions 10.9 and 16.4.

    2.20: Can I initialize unions?

    A: The current C Standard allows an initializer for the first-namedmember.

    2.22: What is the difference between an enumeration and a set ofpreprocessor #defines?

    A: At the present time, there is little difference. The C Standardstates that enumerations are compatible with integral types.

    2.24: Is there an easy way to print enumeration values symbolically?

    17

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    18/56

    A: No.

    Section 3. Expressions

    3.1: Why doesn't the code "a[i] = i++;" work?

    A: The variable i is both referenced and modified in the sameexpression.

    3.2: Under my compiler, the code "int i = 7;printf("%d\n", i++ * i++);" prints 49. Regardless of the orderof evaluation, shouldn't it print 56?

    A: The operations implied by the postincrement and postdecrement

    operators ++ and -- are performed at some time after theoperand's former values are yielded and before the end of theexpression, but not necessarily immediately after, or beforeother parts of the expression are evaluated.

    3.3: What should the code "int i = 3; i = i++;" do?

    A: The expression is undefined.

    3.3b: Here's a slick expression: "a ^= b ^= a ^= b". It swaps a and bwithout using a temporary.

    A: Not portably; its behavior is undefined.

    3.4: Don't precedence and parentheses dictate order of evaluation?

    A: Operator precedence and explicit parentheses impose only apartial ordering on the evaluation of an expression, which doesnot generally include the order of side effects.

    3.5: But what about the && and || operators?

    A: There is a special exception for those operators: left-to-rightevaluation is guaranteed.

    3.8: What's a "sequence point"?

    A: A point (at the end of a full expression, or at the ||, &&, ?:,or comma operators, or just before a function call) at which allside effects are guaranteed to be complete.

    18

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    19/56

    3.9: So given a[i] = i++; we don't know which cell of a[] getswritten to, but i does get incremented by one, right?

    A: *No*. Once an expression or program becomes undefined, *all*

    aspects of it become undefined.

    3.12: If I'm not using the value of the expression, should I use i++or ++i to increment a variable?

    A: Since the two forms differ only in the value yielded, they areentirely equivalent when only their side effect is needed.

    3.14: Why doesn't the code "int a = 1000, b = 1000;long int c = a * b;" work?

    A: You must manually cast one of the operands to (long).

    3.16: Can I use ?: on the left-hand side of an assignment expression?

    A: No.

    Section 4. Pointers

    4.2: What's wrong with "char *p; *p = malloc(10);"?

    A: The pointer you declared is p, not *p.

    4.3: Does *p++ increment p, or what it points to?

    A: *p++ increments p. To increment the value pointed to by p, use(*p)++ .

    4.5: I want to use a char * pointer to step over some ints. Whydoesn't "((int *)p)++;" work?

    A: In C, a cast operator is a conversion operator, and bydefinition it yields an rvalue, which cannot be assigned to, orincremented with ++.

    4.8: I have a function which accepts, and is supposed to initialize,a pointer, but the pointer in the caller remains unchanged.

    A: The called function probably altered only the passed copy of thepointer.

    19

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    20/56

    4.9: Can I use a void ** pointer as a parameter so that a functioncan accept a generic pointer by reference?

    A: Not portably.

    4.10: I have a function which accepts a pointer to an int. How can Ipass a constant like 5 to it?

    A: You will have to declare a temporary variable.

    4.11: Does C even have "pass by reference"?

    A: Not really, though it can be simulated.

    4.12: I've seen different methods used for calling functions via

    pointers.

    A: The extra parentheses and explicit * are now officiallyoptional, although some older implementations require them.

    Section 5. Null Pointers

    5.1: What is this infamous null pointer, anyway?

    A: For each pointer type, there is a special value -- the "nullpointer" -- which is distinguishable from all other pointervalues and which is not the address of any object or function.

    5.2: How do I get a null pointer in my programs?

    A: A constant 0 in a pointer context is converted into a nullpointer at compile time. A "pointer context" is aninitialization, assignment, or comparison with one side avariable or expression of pointer type, and (in ANSI standard C)a function argument which has a prototype in scope declaring acertain parameter as being of pointer type. In other contexts(function arguments without prototypes, or in the variable partof variadic function calls) a constant 0 with an appropriateexplicit cast is required.

    5.3: Is the abbreviated pointer comparison "if(p)" to test for non-null pointers valid?

    A: Yes. The construction "if(p)" works, regardless of the internal

    20

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    21/56

    representation of null pointers, because the compileressentially rewrites it as "if(p != 0)" and goes on to convert 0into the correct null pointer.

    5.4: What is NULL and how is it #defined?

    A: NULL is simply a preprocessor macro, #defined as 0 (or((void *)0)), which is used (as a stylistic convention, inpreference to unadorned 0's) to generate null pointers.

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

    A: The same as on any other machine: as 0. (The compiler makes thetranslation, upon seeing a 0, not the preprocessor; see alsoquestion 5.4.)

    5.6: If NULL were defined as "((char *)0)," wouldn't that makefunction calls which pass an uncast NULL work?

    A: Not in general. The complication is that there are machineswhich use different internal representations for pointers todifferent types of data. A cast is still required to tell thecompiler which kind of null pointer is required, since it may bedifferent from (char *)0.

    5.9: If NULL and 0 are equivalent as null pointer constants, whichshould I use?

    A: Either; the distinction is entirely stylistic.

    5.10: But wouldn't it be better to use NULL, in case the value of NULLchanges?

    A: No. NULL is a constant zero, so a constant zero is equallysufficient.

    5.12: I use the preprocessor macro "#define Nullptr(type) (type *)0"to help me build null pointers of the correct type.

    A: This trick, though valid, does not buy much.

    5.13: This is strange. NULL is guaranteed to be 0, but the nullpointer is not?

    A: A "null pointer" is a language concept whose particular internal

    21

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    22/56

    value does not matter. A null pointer is requested in sourcecode with the character "0". "NULL" is a preprocessor macro,which is always #defined as 0 (or ((void *)0)).

    5.14: Why is there so much confusion surrounding null pointers?

    A: The fact that null pointers are represented both in source code,and internally to most machines, as zero invites unwarrantedassumptions. The use of a preprocessor macro (NULL) may seem tosuggest that the value could change some day, or on some weirdmachine.

    5.15: I'm confused. I just can't understand all this null pointerstuff.

    A: A simple rule is, "Always use `0' or `NULL' for null pointers,

    and always cast them when they are used as arguments in functioncalls."

    5.16: Given all the confusion surrounding null pointers, wouldn't itbe easier simply to require them to be represented internally byzeroes?

    A: Such a requirement would accomplish little.

    5.17: Seriously, have any actual machines really used nonzero nullpointers?

    A: Machines manufactured by Prime, Honeywell-Bull, and CDC, as wellas Symbolics Lisp Machines, have done so.

    5.20: What does a run-time "null pointer assignment" error mean?

    A: It means that you've written, via a null pointer, to an invalidlocation. (See also question 16.8.)

    Section 6. Arrays and Pointers

    6.1: I had the definition char a[6] in one source file, and inanother I declared extern char *a. Why didn't it work?

    A: The declaration extern char *a simply does not match the actualdefinition. Use extern char a[].

    6.2: But I heard that char a[] was identical to char *a.

    22

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    23/56

    A: Not at all. Arrays are not pointers. A reference like x[3]generates different code depending on whether x is an array or apointer.

    6.3: So what is meant by the "equivalence of pointers and arrays" inC?

    A: An lvalue of type array-of-T which appears in an expressiondecays into a pointer to its first element; the type of theresultant pointer is pointer-to-T. So for an array a andpointer p, you can say "p = a;" and then p[3] and a[3] willaccess the same element.

    6.4: Why are array and pointer declarations interchangeable asfunction formal parameters?

    A: It's supposed to be a convenience.

    6.7: How can an array be an lvalue, if you can't assign to it?

    A: An array is not a "modifiable lvalue."

    6.8: What is the real difference between arrays and pointers?

    A: Arrays automatically allocate space which is fixed in size andlocation; pointers are dynamic.

    6.9: Someone explained to me that arrays were really just constantpointers.

    A: An array name is "constant" in that it cannot be assigned to,but an array is *not* a pointer.

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

    A: Yes, array subscripting is commutative in C. The arraysubscripting operation a[e] is defined as being identical to*((a)+(e)).

    6.12: What's the difference between array and &array?

    A: The type.

    6.13: How do I declare a pointer to an array?

    23

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    24/56

    A: Usually, you don't want to. Consider using a pointer to one ofthe array's elements instead.

    6.14: How can I set an array's size at run time?

    A: It's straightforward to use malloc() and a pointer.

    6.15: How can I declare local arrays of a size matching a passed-inarray?

    A: Until recently, you couldn't; array dimensions had to be compile-time constants. C9X will fix this.

    6.16: How can I dynamically allocate a multidimensional array?

    A: The traditional solution is to allocate an array of pointers,and then initialize each pointer to a dynamically-allocated"row." See the full list for code samples.

    6.17: Can I simulate a non-0-based array with a pointer?

    A: Not if the pointer points outside of the block of memory it isintended to access.

    6.18: My compiler complained when I passed a two-dimensional array toa function 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 arrayin C) decays into a pointer to an array, not a pointer to apointer.

    6.19: How do I write functions which accept two-dimensional arrayswhen the width is not known at compile time?

    A: It's not always particularly easy.

    6.20: How can I use statically- and dynamically-allocatedmultidimensional arrays interchangeably when passing them tofunctions?

    A: There is no single perfect method, but see the full list forsome ideas.

    6.21: Why doesn't sizeof properly report the size of an array which is

    24

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    25/56

    a parameter to a function?

    A: The sizeof operator reports the size of the pointer parameterwhich the function actually receives.

    Section 7. Memory Allocation

    7.1: Why doesn't the code "char *answer; gets(answer);" work?

    A: The pointer variable answer has not been set to point to anyvalid storage. The simplest way to correct this fragment is touse a local array, instead of a pointer.

    7.2: I can't get strcat() to work. I tried "char *s3 =strcat(s1, s2);" but I got strange results.

    A: Again, the main problem here is that space for the concatenatedresult is not properly allocated.

    7.3: 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, if only to make sure that the compiler isdoing it for you.

    7.3b: I just tried the code "char *p; strcpy(p, "abc");" and itworked. Why didn't it crash?

    A: You got "lucky".

    7.3c: How much memory does a pointer variable allocate?

    A: Only enough memory to hold the pointer itself, not any memoryfor the pointer to point to.

    7.5a: I have a function that is supposed to return a string, but whenit returns to its caller, the returned string is garbage.

    A: Make sure that the pointed-to memory is properly (i.e. notlocally) allocated.

    7.5b: So what's the right way to return a string?

    A: Return a pointer to a statically-allocated buffer, a buffer

    25

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    26/56

    passed in by the caller, or memory obtained with malloc().

    7.6: Why am I getting "warning: assignment of pointer from integerlacks a cast" for calls to malloc()?

    A: Have you #included ?

    7.7: Why does some code carefully cast the values returned by mallocto the pointer type being allocated?

    A: Before ANSI/ISO C, these casts were required to silence certainwarnings.

    7.8: Why does so much code leave out the multiplication bysizeof(char) when allocating strings?

    A: Because sizeof(char) is, by definition, exactly 1.

    7.14: I've heard that some operating systems don't actually allocatemalloc'ed memory until the program tries to use it. Is thislegal?

    A: It's hard to say.

    7.16: I'm allocating a large array for some numeric work, but malloc()is acting strangely.

    A: Make sure the number you're trying to pass to malloc() isn'tbigger than a size_t can hold.

    7.17: I've got 8 meg of memory in my PC. Why can I only seem tomalloc 640K or so?

    A: Under the segmented architecture of PC compatibles, it can bedifficult to use more than 640K with any degree of transparency.See also question 19.23.

    7.19: My program is crashing, apparently somewhere down inside malloc.

    A: Make sure you aren't using more memory than you malloc'ed,especially for strings (which need strlen(str) + 1 bytes).

    7.20: You can't use dynamically-allocated memory after you free it,can you?

    A: No. Some early documentation implied otherwise, but the claim

    26

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    27/56

    is no longer valid.

    7.21: Why isn't a pointer null after calling free()?

    A: C's pass-by-value semantics mean that called functions can never

    permanently change the values of their arguments.

    7.22: When I call malloc() to allocate memory for a local pointer, doI have to explicitly free() it?

    A: Yes.

    7.23: When I free a dynamically-allocated structure containingpointers, do I also have to free each subsidiary pointer?

    A: Yes.

    7.24: Must I free allocated memory before the program exits?

    A: You shouldn't have to.

    7.25: Why doesn't my program's memory usage go down when I freememory?

    A: Most implementations of malloc/free do not return freed memoryto the operating system.

    7.26: How does free() know how many bytes to free?

    A: The malloc/free implementation remembers the size of each blockas it is allocated.

    7.27: So can I query the malloc package to find out how big anallocated block is?

    A: Not portably.

    7.30: Is it legal to pass a null pointer as the first argument torealloc()?

    A: ANSI C sanctions this usage, although several earlierimplementations do not support it.

    7.31: What's the difference between calloc() and malloc()?

    A: calloc() takes two arguments, and initializes the allocated

    27

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    28/56

    memory to all-bits-0.

    7.32: What is alloca() and why is its use discouraged?

    A: alloca() allocates memory which is automatically freed when the

    function which called alloca() returns. alloca() cannot bewritten portably, is difficult to implement on machines withouta stack, and fails under certain conditions if implementedsimply.

    Section 8. Characters and Strings

    8.1: Why doesn't "strcat(string, '!');" work?

    A: strcat() concatenates *strings*, not characters.

    8.2: Why won't the test if(string == "value") correctly comparestring against the value?

    A: It's comparing pointers. To compare two strings, use strcmp().

    8.3: Why can't I assign strings to character arrays?

    A: Strings are arrays, and you can't assign arrays directly. Usestrcpy() instead.

    8.6: How can I get the numeric (character set) value corresponding toa character?

    A: In C, if you have the character, you have its value.

    8.9: Why is sizeof('a') not 1?

    A: Character constants in C are of type int.

    Section 9. Boolean Expressions and Variables

    9.1: What is the right type to use for Boolean values in C?

    A: There's no one right answer; see the full list for somediscussion.

    9.2: What if a built-in logical or relational operator "returns"something other than 1?

    28

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    29/56

    A: When a Boolean value is generated by a built-in operator, it isguaranteed to be 1 or 0. (This is *not* true for some libraryroutines such as isalpha.)

    9.3: Is if(p), where p is a pointer, valid?

    A: Yes. See question 5.3.

    Section 10. C Preprocessor

    10.2: I've got some cute preprocessor macros that let me write C codethat looks more like Pascal. What do y'all think?

    A: Bleah.

    10.3: How can I write a generic macro to swap two values?

    A: There is no good answer to this question. The best all-aroundsolution is probably to forget about using a macro.

    10.4: What's the best way to write a multi-statement macro?

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

    10.6: What are .h files and what should I put in them?

    A: Header files (also called ".h files") should generally containcommon declarations and macro, structure, and typedefdefinitions, but not variable or function definitions.

    10.7: Is it acceptable for one header file to #include another?

    A: It's a question of style, and thus receives considerable debate.

    10.8a: What's the difference between #include and #include "" ?

    A: Roughly speaking, the syntax is for Standard headers and ""is for project headers.

    10.8b: What are the complete rules for header file searching?

    A: The exact behavior is implementation-defined; see the full listfor some discussion.

    29

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    30/56

    10.9: I'm getting strange syntax errors on the very first declarationin a file, but it looks fine.

    A: Perhaps there's a missing semicolon at the end of the lastdeclaration in the last header file you're #including.

    10.10b: I'm #including the header file for a function, but the linkerkeeps saying it's undefined.

    A: See question 13.25.

    10.11: Where can I get a copy of a missing header file?

    A: Contact your vendor, or see question 18.16 or the full list.

    10.12: How can I construct preprocessor #if expressions which compare

    strings?

    A: You can't do it directly; try #defining several manifestconstants and implementing conditionals on those.

    10.13: Does the sizeof operator work in preprocessor #if directives?

    A: No.

    10.14: Can I use an #ifdef in a #define line, to define something twodifferent ways?

    A: No.

    10.15: Is there anything like an #ifdef for typedefs?

    A: Unfortunately, no.

    10.16: How can I use a preprocessor #if expression to detectendianness?

    A: You probably can't.

    10.18: How can I preprocess some code to remove selected conditionalcompilations, without preprocessing everything?

    A: Look for a program called unifdef, rmifdef, or scpp.

    10.19: How can I list all of the predefined identifiers?

    30

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    31/56

    A: If the compiler documentation is unhelpful, try extractingprintable strings from the compiler or preprocessor executable.

    10.20: I have some old code that tries to construct identifiers with amacro like "#define Paste(a, b) a/**/b", but it doesn't work any

    more.

    A: Try the ANSI token-pasting operator ##.

    10.22: What does the message "warning: macro replacement within astring literal" mean?

    A: See question 11.18.

    10.23-4: I'm having trouble using macro arguments inside stringliterals, using the `#' operator.

    A: See questions 11.17 and 11.18.

    10.25: I've got this tricky preprocessing I want to do and I can'tfigure out a way to do it.

    A: Consider writing your own little special-purpose preprocessingtool, instead.

    10.26: How can I write a macro which takes a variable number ofarguments?

    A: Here is one popular trick. Note that the parentheses aroundprintf's argument list are in the macro call, not thedefinition.

    #define DEBUG(args) (printf("DEBUG: "), printf args)

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

    Section 11. ANSI/ISO Standard C

    11.1: What is the "ANSI C Standard?"

    A: In 1983, the American National Standards Institute (ANSI)commissioned a committee to standardize the C language. Theirwork was ratified as ANS X3.159-1989, and has since been adoptedas ISO/IEC 9899:1990, and later amended.

    31

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    32/56

    11.2: How can I get a copy of the Standard?

    A: Copies are available from ANSI in New York, or from GlobalEngineering Documents in Englewood, CO, or from any nationalstandards body, or from ISO in Geneva, or republished within one

    or more books. See the unabridged list for details.

    11.2b: Where can I get information about updates to the Standard?

    A: See the full list for pointers.

    11.3: My ANSI compiler is complaining about prototype mismatches forparameters declared float.

    A: You have mixed the new-style prototype declaration"extern int func(float);" with the old-style definition

    "int func(x) float x;". "Narrow" types are treated differentlyaccording to which syntax is used. This problem can be fixed byavoiding narrow types, or by using either new-style (prototype)or old-style syntax consistently.

    11.4: Can you mix old-style and new-style function syntax?

    A: Doing so is currently legal, for most argument types(see question 11.3).

    11.5: Why does the declaration "extern int f(struct x *p);" give me awarning message?

    A: A structure declared (or even mentioned) for the first timewithin a prototype cannot be compatible with other structuresdeclared in the same source file.

    11.8: Why can't I use const values in initializers and arraydimensions?

    A: The value of a const-qualified object is *not* a constantexpression in the full sense of the term.

    11.9: What's the difference between "const char *p" and"char * const p"?

    A: The former declares a pointer to a constant character; thelatter declares a constant pointer to a character.

    11.10: Why can't I pass a char ** to a function which expects a

    32

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    33/56

    const char **?

    A: The rule which permits slight mismatches in qualified pointerassignments is not applied recursively.

    11.12a: What's the correct declaration of main()?

    A: int main(int argc, char *argv[]) .

    11.12b: Can I declare main() as void, to shut off these annoying "mainreturns no value" messages?

    A: No.

    11.13: But what about main's third argument, envp?

    A: It's a non-standard (though common) extension.

    11.14: I believe that declaring void main() can't fail, since I'mcalling exit() instead of returning.

    A: It doesn't matter whether main() returns or not, the problem isthat its caller may not even be able to *call* it correctly.

    11.15: The book I've been using always uses void main().

    A: It's wrong.

    11.16: Is exit(status) truly equivalent to returning the same statusfrom main()?

    A: Yes and no. (See the full list for details.)

    11.17: How do I get the ANSI "stringizing" preprocessing operator `#'to stringize the macro's value instead of its name?

    A: You can use a two-step #definition to force a macro to beexpanded as well as stringized.

    11.18: What does the message "warning: macro replacement within astring literal" mean?

    A: Some pre-ANSI compilers/preprocessors expanded macro parameterseven inside string literals and character constants.

    11.19: I'm getting strange syntax errors inside lines I've #ifdeffed

    33

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    34/56

    out.

    A: Under ANSI C, #ifdeffed-out text must still consist of "validpreprocessing tokens." This means that there must be nonewlines inside quotes, and no unterminated comments or quotes

    (i.e. no single apostrophes).

    11.20: What are #pragmas ?

    A: The #pragma directive provides a single, well-defined "escapehatch" which can be used for extensions.

    11.21: What does "#pragma once" mean?

    A: It is an extension implemented by some preprocessors to helpmake header files idempotent.

    11.22: Is char a[3] = "abc"; legal?

    A: Yes, in ANSI C.

    11.24: Why can't I perform arithmetic on a void * pointer?

    A: The compiler doesn't know the size of the pointed-to objects.

    11.25: What's the difference between memcpy() and memmove()?

    A: memmove() offers guaranteed behavior if the source anddestination arguments overlap.

    11.26: What should malloc(0) do?

    A: The behavior is implementation-defined.

    11.27: Why does the ANSI Standard not guarantee more than six case-insensitive characters of external identifier significance?

    A: The problem is older linkers which cannot be forced (by merewords in a Standard) to upgrade.

    11.29: My compiler is rejecting the simplest possible test programs,with all kinds of syntax errors.

    A: Perhaps it is a pre-ANSI compiler.

    11.30: Why are some ANSI/ISO Standard library functions showing up as

    34

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    35/56

    undefined, even though I've got an ANSI compiler?

    A: Perhaps you don't have ANSI-compatible headers and libraries.

    11.31: Does anyone have a tool for converting old-style C programs to

    ANSI C, or for automatically generating prototypes?

    A: See the full list for details.

    11.32: Why won't frobozz-cc, which claims to be ANSI compliant, acceptthis code?

    A: Are you sure that the code being rejected doesn't rely on somenon-Standard extension?

    11.33: What's the difference between implementation-defined,

    unspecified, and undefined behavior?

    A: If you're writing portable code, ignore the distinctions.Otherwise, see the full list.

    11.34: I'm appalled that the ANSI Standard leaves so many issuesundefined.

    A: In most of these cases, the Standard is simply codifyingexisting practice.

    11.35: I just tried some allegedly-undefined code on an ANSI-conformingcompiler, and got the results I expected.

    A: A compiler may do anything it likes when faced with undefinedbehavior, including doing what you expect.

    Section 12. Stdio

    12.1: What's wrong with the code "char c; while((c = getchar()) !=EOF) ..."?

    A: The variable to hold getchar's return value must be an int.

    12.2: Why won't the code "while(!feof(infp)) {fgets(buf, MAXLINE, infp); fputs(buf, outfp); }" work?

    A: EOF is only indicated *after* an input routine fails.

    35

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    36/56

    12.4: My program's prompts and intermediate output don't always showup on the screen.

    A: It's best to use an explicit fflush(stdout) whenever outputshould definitely be visible.

    12.5: How can I read one character at a time, without waiting for theRETURN key?

    A: See question 19.1.

    12.6: How can I print a '%' character with printf?

    A: "%%".

    12.9: How can printf() use %f for type double, if scanf() requires

    %lf?

    A: C's "default argument promotions" mean that values of type floatare promoted to double.

    12.9b: What printf format should I use for a typedef when I don't knowthe underlying type?

    A: Use a cast to convert the value to a known type, then use theprintf format matching that type.

    12.10: How can I implement a variable field width with printf?

    A: Use printf("%*d", width, x).

    12.11: How can I print numbers with commas separating the thousands?

    A: There is no standard routine (but see ).

    12.12: Why doesn't the call scanf("%d", i) work?

    A: The arguments you pass to scanf() must always be pointers.

    12.13: Why doesn't the code "double d; scanf("%f", &d);" work?

    A: Unlike printf(), scanf() uses %lf for double, and %f for float.

    12.15: How can I specify a variable width in a scanf() format string?

    A: You can't.

    36

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    37/56

    12.17: When I read numbers from the keyboard with scanf "%d\n", itseems to hang until I type one extra line of input.

    A: Try using "%d" instead of "%d\n".

    12.18: I'm reading a number with scanf %d and then a string withgets(), but the compiler seems to be skipping the call togets()!

    A: scanf() and gets() do not work well together.

    12.19: I'm re-prompting the user if scanf() fails, but sometimes itseems to go into an infinite loop.

    A: scanf() tends to "jam" on bad input since it does not discard

    it.

    12.20: Why does everyone say not to use scanf()? What should I useinstead?

    A: scanf() has a number of problems. Usually, it's easier to readentire lines and then interpret them.

    12.21: How can I tell how much destination buffer space I'll need foran arbitrary sprintf call? How can I avoid overflowing thedestination buffer with sprintf()?

    A: Use the new snprintf() function, if you can.

    12.23: Why does everyone say not to use gets()?

    A: It cannot be prevented from overflowing the input buffer.

    12.24: Why does errno contain ENOTTY after a call to printf()?

    A: Don't worry about it. It is only meaningful for a program toinspect the contents of errno after an error has been reported.

    12.25: What's the difference between fgetpos/fsetpos and ftell/fseek?

    A: fgetpos() and fsetpos() use a special typedef which may allowthem to work with larger files than ftell() and fseek().

    12.26: Will fflush(stdin) flush unread characters from the standardinput stream?

    37

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    38/56

    A: No.

    12.30: I'm trying to update a file in place, by using fopen mode "r+",but it's not working.

    A: Be sure to call fseek between reading and writing.

    12.33: How can I redirect stdin or stdout from within a program?

    A: Use freopen().

    12.34: Once I've used freopen(), how can I get the original streamback?

    A: There isn't a good way. Try avoiding freopen.

    12.36b: How can I arrange to have output go two places at once?

    A: You could write your own printf variant which printed everythingtwice. See question 15.5.

    12.38: How can I read a binary data file properly?

    A: Be sure to specify "rb" mode when calling fopen().

    Section 13. Library Functions

    13.1: How can I convert numbers to strings?

    A: Just use sprintf().

    13.2: Why does strncpy() not always write a '\0'?

    A: For mildly-interesting historical reasons.

    13.5: Why do some versions of toupper() act strangely if given anupper-case letter?

    A: Older versions of toupper() and tolower() did not always work asexpected in this regard.

    13.6: How can I split up a string into whitespace-separated fields?

    A: Try strtok().

    38

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    39/56

    13.7: I need some code to do regular expression and wildcard matching.

    A: regexp libraries abound; see the full list for details.

    13.8: I'm trying to sort an array of strings with qsort(), usingstrcmp() as the comparison function, but it's not working.

    A: You'll have to write a "helper" comparison function which takestwo generic pointer arguments, converts them to char **, anddereferences them, yielding char *'s which can be usefullycompared.

    13.9: Now I'm trying to sort an array of structures, but the compileris complaining that the function is of the wrong type forqsort().

    A: The comparison function must be declared as accepting "genericpointers" (const void *) which it then converts to structurepointers.

    13.10: How can I sort a linked list?

    A: Algorithms like insertion sort and merge sort work well, or youcan keep the list in order as you build it.

    13.11: How can I sort more data than will fit in memory?

    A: You want an "external sort"; see the full list for details.

    13.12: How can I get the time of day in a C program?

    A: Just use the time(), ctime(), localtime() and/or strftime()functions.

    13.13: How can I convert a struct tm or a string into a time_t?

    A: The ANSI mktime() function converts a struct tm to a time_t. Nostandard routine exists to parse strings.

    13.14: How can I perform calendar manipulations?

    A: The ANSI/ISO Standard C mktime() and difftime() functionsprovide some support for both problems.

    13.14b: Does C have any Year 2000 problems?

    39

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    40/56

    A: No, although poorly-written C programs do. Make sure you knowthat tm_year holds the value of the year minus 1900.

    13.15: I need a random number generator.

    A: The Standard C library has one: rand().

    13.16: How can I get random integers in a certain range?

    A: One method is something like

    (int)((double)rand() / ((double)RAND_MAX + 1) * N)

    13.17: Each time I run my program, I get the same sequence of numbersback from rand().

    A: You can call srand() to seed the pseudo-random number generatorwith a truly random initial value.

    13.18: I need a random true/false value, so I'm just taking rand() % 2,but it's alternating 0, 1, 0, 1, 0...

    A: Try using the higher-order bits: see question 13.16.

    13.20: How can I generate random numbers with a normal or Gaussiandistribution?

    A: See the longer versions of this list for ideas.

    13.24: I'm trying to port this old program. Why do I get "undefinedexternal" errors for some library functions?

    A: Some semistandard functions have been renamed or replaced overthe years; see the full list for details.

    13.25: I get errors due to library functions being undefined eventhough I #include the right header files.

    A: You may have to explicitly ask for the correct libraries to besearched.

    13.26: I'm still getting errors due to library functions beingundefined, even though I'm requesting the right libraries.

    A: Library search order is significant; usually, you must search

    40

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    41/56

    the libraries last.

    13.28: What does it mean when the linker says that _end is undefined?

    A: You generally get that message only when other symbols are

    undefined, too.

    Section 14. Floating Point

    14.1: When I set a float variable to 3.1, why is printf printing it as3.0999999?

    A: Most computers use base 2 for floating-point numbers, and manyfractions (including 0.1 decimal) are not exactly representablein base 2.

    14.2: Why is sqrt(144.) giving me crazy numbers?

    A: Make sure that you have #included , and correctlydeclared other functions returning double.

    14.3: I keep getting "undefined: sin" compilation errors.

    A: Make sure you're actually linking with the math library.

    14.4: My floating-point calculations are acting strangely and givingme different answers on different machines.

    A: First, see question 14.2 above. If the problem isn't thatsimple, see the full list for a brief explanation, or any goodprogramming book for a better one.

    14.5: What's a good way to check for "close enough" floating-pointequality?

    A: The best way is to use an accuracy threshold which is relativeto the magnitude of the numbers being compared.

    14.6: How do I round numbers?

    A: For positive numbers, try (int)(x + 0.5) .

    14.7: Where is C's exponentiation operator?

    A: Try using the pow() function.

    41

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    42/56

    14.8: The predefined constant M_PI seems to be missing from .

    A: That constant is not standard.

    14.9: How do I test for IEEE NaN and other special values?

    A: There is not yet a portable way, but see the full list forideas.

    14.11: What's a good way to implement complex numbers in C?

    A: It is straightforward to define a simple structure and somearithmetic functions to manipulate them.

    14.12: I'm looking for some mathematical library code.

    A: See Ajay Shah's index of free numerical software atftp://ftp.math.psu.edu/pub/FAQ/numcomp-free-c .

    14.13: I'm having trouble with a Turbo C program which crashes and sayssomething like "floating point formats not linked."

    A: You may have to insert a dummy call to a floating-point libraryfunction to force loading of floating-point support.

    Section 15. Variable-Length Argument Lists

    15.1: I heard that you have to #include before callingprintf(). Why?

    A: So that a proper prototype for printf() will be in scope.

    15.2: How can %f be used for both float and double arguments inprintf()?

    A: In variable-length argument lists, types char and short int arepromoted to int, and float is promoted to double.

    15.3: Why don't function prototypes guard against mismatches inprintf's arguments?

    A: Function prototypes do not provide any information about thenumber and types of variable arguments.

    42

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    43/56

    15.4: How can I write a function that takes a variable number ofarguments?

    A: Use the header.

    15.5: 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().

    15.6: How can I write a function analogous to scanf(), that callsscanf() to do most of the work?

    A: C9X will support vscanf().

    15.7: I have a pre-ANSI compiler, without . What can I do?

    A: There's an older header, , which offers about thesame functionality.

    15.8: How can I discover how many arguments a function was actuallycalled with?

    A: Any function which takes a variable number of arguments must beable to determine *from the arguments' values* how many of themthere are.

    15.9: My compiler isn't letting me declare a function that accepts*only* variable arguments.

    A: Standard C requires at least one fixed argument.

    15.10: Why isn't "va_arg(argp, float)" working?

    A: Because the "default argument promotions" apply in variable-length argument lists, you should always useva_arg(argp, double).

    15.11: I can't get va_arg() to pull in an argument of type pointer-to-function.

    A: Use a typedef.

    15.12: How can I write a function which takes a variable number ofarguments and passes them to some other function ?

    43

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    44/56

    A: In general, you cannot.

    15.13: How can I call a function with an argument list built up at runtime?

    A: You can't.

    Section 16. Strange Problems

    16.1b: I'm getting baffling syntax errors which make no sense at all,and it seems like large chunks of my program aren't beingcompiled.

    A: Check for unclosed comments or mismatched preprocessing

    directives.

    16.1c: Why isn't my procedure call working?

    A: Function calls always require parenthesized argument lists.

    16.3: This program crashes before it even runs!

    A: Look for very large, local arrays.(See also questions 11.12b, 16.4, 16.5, and 18.4.)

    16.4: I have a program that seems to run correctly, but then crashesas it's exiting.

    A: See the full list for ideas.

    16.5: This program runs perfectly on one machine, but I get weirdresults on another.

    A: See the full list for a brief list of possibilities.

    16.6: Why does the code "char *p = "hello, world!"; p[0] = 'H';"crash?

    A: String literals are not modifiable, except (in effect) when theyare used as array initializers.

    16.8: What does "Segmentation violation" mean?

    A: It generally means that your program tried to access memory it

    44

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    45/56

    shouldn't have, invariably as a result of stack corruption orimproper pointer use.

    Section 17. Style

    17.1: What's the best style for code layout in C?

    A: There is no one "best style," but see the full list for a fewsuggestions.

    17.3: Is the code "if(!strcmp(s1, s2))" good style?

    A: Not particularly.

    17.4: Why do some people write if(0 == x) instead of if(x == 0)?

    A: It's a trick to guard against the common error of writingif(x = 0) .

    17.5: I came across some code that puts a (void) cast before each callto printf(). Why?

    A: To suppress warnings about otherwise discarded return values.

    17.8: What is "Hungarian Notation"?

    A: It's a naming convention which encodes information about avariable's type in its name.

    17.9: Where can I get the "Indian Hill Style Guide" and other codingstandards?

    A: See the unabridged list.

    17.10: Some people say that goto's are evil and that I should never usethem. Isn't that a bit extreme?

    A: Yes. Absolute rules are an imperfect approach to goodprogramming style.

    Section 18. Tools and Resources

    18.1: I'm looking for C development tools (cross-reference generators,code beautifiers, etc.).

    45

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    46/56

    A: See the full list for a few names.

    18.2: How can I track down these pesky malloc problems?

    A: See the full list for a list of tools.

    18.3: What's a free or cheap C compiler I can use?

    A: See the full list for a brief catalog.

    18.4: I just typed in this program, and it's acting strangely. Canyou see anything wrong with it?

    A: See if you can run lint first.

    18.5: How can I shut off the "warning: possible pointer alignmentproblem" message which lint gives me for each call to malloc()?

    A: It may be easier simply to ignore the message, perhaps in anautomated way with grep -v.

    18.7: Where can I get an ANSI-compatible lint?

    A: See the unabridged list for two commercial products.

    18.8: Don't ANSI function prototypes render lint obsolete?

    A: No. A good compiler may match most of lint's diagnostics; fewprovide all.

    18.9: Are there any C tutorials or other resources on the net?

    A: There are several of them.

    18.10: What's a good book for learning C?

    A: There are far too many books on C to list here; the full listcontains a few pointers.

    18.13: Where can I find the sources of the standard C libraries?

    A: Several possibilites are listed in the full list.

    18.13b: Is there an on-line C reference manual?

    46

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    47/56

    A: Two possibilities arehttp://www.cs.man.ac.uk/standard_c/_index.html andhttp://www.dinkumware.com/htm_cl/index.html .

    18.13c: Where can I get a copy of the ANSI/ISO C Standard?

    A: See question 11.2.

    18.14: I need code to parse and evaluate expressions.

    A: Several available packages are mentioned in the full list.

    18.15: Where can I get a BNF or YACC grammar for C?

    A: See the ANSI Standard, or the unabridged list.

    18.15b: Does anyone have a C compiler test suite I can use?

    A: See the full list for several sources.

    18.15c: Where are some collections of useful code fragments andexamples?

    A: See the full list for a few sources.

    18.15d: I need code for performing multiple precision arithmetic.

    A: See the full list for a few ideas.

    18.16: Where and how can I get copies of all these freely distributableprograms?

    A: See the regular postings in the comp.sources.unix andcomp.sources.misc newsgroups, or the full version of this list,for information.

    Section 19. System Dependencies

    19.1: How can I read a single character from the keyboard withoutwaiting for the RETURN key?

    A: Alas, there is no standard or portable way to do this sort ofthing in C.

    19.2: How can I find out how many characters are available for

    47

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    48/56

    reading, or do a non-blocking read?

    A: These, too, are entirely operating-system-specific.

    19.3: How can I display a percentage-done indication that updates

    itself in place, or show one of those "twirling baton" progressindicators?

    A: The character '\r' is a carriage return, and '\b' is abackspace.

    19.4: How can I clear the screen, or print text in color, or move thecursor?

    A: The only halfway-portable solution is the curses library.

    19.5: How do I read the arrow keys? What about function keys?

    A: Such things depend on the keyboard, operating system, andlibrary you're using.

    19.6: How do I read the mouse?

    A: What system are you using?

    19.7: How can I do serial ("comm") port I/O?

    A: It's system-dependent.

    19.8: How can I direct output to the printer?

    A: See the full list for ideas.

    19.9: How do I send escape sequences to control a terminal or otherdevice?

    A: By sending them. ESC is '\033' in ASCII.

    19.10: How can I do graphics?

    A: There is no portable way.

    19.11: How can I check whether a file exists?

    A: You can try the access() or stat() functions. Otherwise, theonly guaranteed and portable way is to try opening the file.

    48

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    49/56

    19.12: How can I find out the size of a file, prior to reading it in?

    A: You might be able to get an estimate using stat() or fseek/ftell(but see the full list for caveats).

    19.12b: How can I find the modification date of a file?

    A: Try stat().

    19.13: How can a file be shortened in-place without completely clearingor rewriting it?

    A: There are various ways to do this, but there is no portablesolution.

    19.14: How can I insert or delete a line in the middle of a file?

    A: Short of rewriting the file, you probably can't.

    19.15: How can I recover the file name given an open file descriptor?

    A: This problem is, in general, insoluble. It is best to rememberthe names of files yourself as you open them

    19.16: How can I delete a file?

    A: The Standard C Library function is remove().

    19.16b: How do I copy files?

    A: Open the source and destination files and copy a character orblock at a time, or see question 19.27.

    19.17: What's wrong with the call fopen("c:\newdir\file.dat", "r")?

    A: You probably need to double those backslashes.

    19.18: How can I increase the allowable number of simultaneously openfiles?

    A: Check your system documentation.

    19.20: How can I read a directory in a C program?

    A: See if you can use the opendir() and readdir() functions.

    49

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    50/56

    19.22: How can I find out how much memory is available?

    A: Your operating system may provide a routine which returns thisinformation.

    19.23: How can I allocate arrays or structures bigger than 64K?

    A: Some operating systems won't let you.

    19.24: What does the error message "DGROUP exceeds 64K" mean?

    A: It means that you have too much static data.

    19.25: How can I access memory located at a certain address?

    A: Set a pointer to the absolute address.

    19.27: How can I invoke another program from within a C program?

    A: Use system().

    19.30: How can I invoke another program and trap its output?

    A: Unix and some other systems provide a popen() function.

    19.31: How can my program discover the complete pathname to theexecutable from which it was invoked?

    A: argv[0] may contain all or part of the pathname. You may beable to duplicate the command language interpreter's search pathlogic to locate the executable.

    19.32: How can I automatically locate a program's configuration filesin the same directory as the executable?

    A: It's hard; see also question 19.31 above.

    19.33: How can a process change an environment variable in its caller?

    A: If it's possible to do so at all, it's system dependent.

    19.36: How can I read in an object file and jump to locations in it?

    A: You want a dynamic linker or loader.

    50

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    51/56

    19.37: How can I implement a delay, or time a user's response, with sub-second resolution?

    A: Unfortunately, there is no portable way.

    19.38: How can I trap or ignore keyboard interrupts like control-C?

    A: Use signal().

    19.39: How can I handle floating-point exceptions gracefully?

    A: Take a look at matherr() and signal(SIGFPE).

    19.40: How do I... Use sockets? Do networking? Write client/serverapplications?

    A: These questions have more to do with the networking facilitiesyou have available than they do with C.

    19.40b: How do I... Use BIOS calls? Write ISR's? Create TSR's?

    A: These are very particular to a particular system.

    19.40c: I'm trying to compile a program in which "union REGS" andint86() are undefined.

    A: Those have to do with MS-DOS interrupt programming.

    19.41: But I can't use all these nonstandard, system-dependentfunctions, because my program has to be ANSI compatible!

    A: That's an impossible requirement. Any real program requires atleast a few services which ANSI doesn't define.

    Section 20. Miscellaneous

    20.1: How can I return multiple values from a function?

    A: Either pass pointers to several locations which the function canfill in, or have the function return a structure containing thedesired values.

    20.3: How do I access command-line arguments?

    A: Via main()'s argv parameter.

    51

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    52/56

    20.5: How can I write data files which can be read on other machineswith different data formats?

    A: The most portable solution is to use text files.

    20.6: How can I call a function, given its name as a string?

    A: The most straightforward thing to do is to maintain acorrespondence table of names and function pointers.

    20.8: How can I implement sets or arrays of bits?

    A: Use arrays of char or int, with a few macros to access thedesired bit at the proper index.

    20.9: How can I determine whether a machine's byte order is big-endianor little-endian?

    A: The usual tricks involve pointers or unions.

    20.10: How can I convert integers to binary or hexadecimal?

    A: Internally, integers are already in binary. During I/O, you maybe able to select a base.

    20.11: Can I use base-2 constants (something like 0b101010)?Is there a printf() format for binary?

    A: No, on both counts.

    20.12: What is the most efficient way to count the number of bits whichare set in an integer?

    A: Many "bit-fiddling" problems like this one can be sped up andstreamlined using lookup tables.

    20.13: What's the best way of making my program efficient?

    A: By picking good algorithms and implementing them carefully.

    20.14: Are pointers really faster than arrays? How much do functioncalls slow things down?

    A: Precise answers to these and many similar questions depend onthe processor and compiler in use.

    52

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    53/56

    20.15b: People claim that optimizing compilers are good, but mine can'teven replace i/=2 with a shift.

    A: Was i signed or unsigned?

    20.15c: How can I swap two values without using a temporary?

    A: The "clever" trick is a ^= b; b ^= a; a ^= b; see also question3.3b.

    20.17: Is there a way to switch on strings?

    A: Not directly.

    20.18: Is there a way to have non-constant case labels (i.e. ranges or

    arbitrary expressions)?

    A: No.

    20.19: Are the outer parentheses in return statements really optional?

    A: Yes.

    20.20: Why don't C comments nest? Are they legal inside quotedstrings?

    A: C comments don't nest because PL/I's comments don't either. Thecharacter sequences /* and */ are not special within double-quoted strings.

    20.20b: What does a+++++b mean ?

    A: Nothing. It's interpreted as "a ++ ++ + b", and cannot beparsed.

    20.24: Why doesn't C have nested functions?

    A: They were deliberately left out of C as a simplification.

    20.24b: What is assert()?

    A: It is a macro which documents an assumption being made by theprogrammer; it terminates the program if the assumption isviolated.

    53

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    54/56

    20.25: How can I call FORTRAN (C++, BASIC, Pascal, Ada, LISP) functionsfrom C?

    A: The answer is entirely dependent on the machine and the specificcalling sequences of the various compilers in use.

    20.26: Does anyone know of a program for converting Pascal or FORTRANto C?

    A: Several freely distributable programs are available, namelyptoc, p2c, and f2c. See the full list for details.

    20.27: Can I use a C++ compiler to compile C code?

    A: Not necessarily; C++ is not a strict superset of C.

    20.28: I need to compare two strings for close, but not necessarilyexact, equality.

    A: See the full list for ideas.

    20.29: What is hashing?

    A: A mapping of strings (or other data structures) to integers, foreasier searching.

    20.31: How can I find the day of the week given the date?

    A: Use mktime(), Zeller's congruence, or some code in the fulllist.

    20.32: Will 2000 be a leap year?

    A: Yes.

    20.34: How do you write a program which produces its own source code asoutput?

    A: Here's one:

    char*s="char*s=%c%s%c;main(){printf(s,34,s,34);}";main(){printf(s,34,s,34);}

    20.35: What is "Duff's Device"?

    A: It's a devastatingly deviously unrolled byte-copying loop. See

    54

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    55/56

    the full list for details.

    20.36: When will the next Obfuscated C Code Contest be held?How can I get a copy of previous winning entries?

    A: See the full list, or http://www.ioccc.org/index.html .

    20.37: What was the entry keyword mentioned in K&R1?

    A: It was reserved to allow functions with multiple, differently-named entry points, but it has been withdrawn.

    20.38: Where does the name "C" come from, anyway?

    A: C was derived from B, which was inspired by BCPL, which was asimplification of CPL.

    20.39: How do you pronounce "char"?

    A: Like the English words "char," "care," or "car" (your choice).

    20.39b: What do "lvalue" and "rvalue" mean?

    A: An "lvalue" denotes an object that has a location; an "rvalue"is any expression that has a value.

    20.40: Where can I get extra copies of this list?

    A: An up-to-date copy may be obtained from ftp.eskimo.com indirectory u/s/scs/C-faq/. You can also just pull it off thenet; the unabridged version is normally posted on the first ofeach month, with an Expires: line which should keep it aroundall month. It is also posted to the newsgroups comp.answers andnews.answers . Several sites archive news.answers postings andother FAQ lists, including this one; two sites are rtfm.mit.edu(directory pub/usenet), and ftp.uu.net (directory usenet).

    A hypertext version of this FAQ list is available athttp://www.eskimo.com/~scs/C-faq/top.html .An extended version has been published by Addison-Wesleyas _C Programming FAQs: Frequently Asked Questions_(ISBN 0-201-84519-9).

    Steve [email protected]

    55

  • 8/8/2019 The Top 10 Ways to Get Screwed by The

    56/56

    Volatile

    Consider the following code fragments:volatile unsigned int done;

    main(){

    done = FALSE;

    while (!done) ;}

    @interrupt void tic2_isr(void){

    second = TC2;TFLG1 = 0x04;done = TRUE;

    }An optimizing compiler knows that done will not change in the main() function. It maydecide that, since done is FALSE in the main() function, and nothing in the main()function changes the value of done, then done will always be FALSE, so there is no needto check if it will ever become TRUE. An optimizing comiler might change the line

    while (!done) ;to

    while (TRUE) ;and the program will never get beyond that line.By declaring done to be volatile, you tell the compiler that the value of done mightchange somewhere else other than in the main() function (such as in an interrupt serviceroutine), and the compiler should not optimize on the done variable.