| Get Screwed with C programming |
|
|
|
![]()
if(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 theassignment operator is too easy to confuse with the equality operator;or maybe the bug is that C doesn't much care what constitutes a booleanexpression: (a=b) is not a boolean expression! (but C doesn'tcare). Closely related to this lack of rigor in booleans, consider thisconstruction: if( 0 < a < 5) c; /* this "boolean" is always true! */ Always true because (0 Or consider this: if( a =! b)c; /* this is compiled as (a = !b), anassignment, rather than (a != b) or (a == !b) */
becomes x=(char)y>>8 /*probablynot what you want */ Suppose foo.h contains:
now, F1. and F2 disagree about the fundamental attributes of structure"foo". If they talk to each other, You Lose! Suppose you write this
Generally speaking, C compilers, and C runtimes either can't or don'ttell you there is anything wrong. What actually happens depends on theparticular C compiler and what trash happened to be left lying aroundwherever the caller is going to look for the returned value. Dependingon how unlucky you are, the program may even appear to work for awhile. Now, imagine the havoc that can ensue if "foo" was thought toreturn a pointer! Consider this bit packing struct:
Depending on which C compiler, and which "endian" flavor of machine youare on, this might actually be implemented as <10-bits><6-bits> or as
foo(pointer->member, pointer = &buffer[0]); Works with gcc (and other compilers I used until I tried acc) and doesnot with acc. The reason is that gcc evaluates function arguments fromleft to right, while acc evaluates arguments from right to left. K&R and ANSI/ISO C specifications do not define the order ofevaluation for function arguments. It can be left-to-right,right-to-left or anything else and is "unspecified". Thus any codewhich relies on this order of evaluation is doomed to be non portable,even across compilers on the same platform. This isn't an entirely non controversial point of view.
which, when adding debugging statements, becomes
There is a large class of similar errors, involving misplacedsemicolons and brackets. 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 theextra stuff so I removed the macro invocation, yielding: functionName,(arg1,arg2,arg3); Oops. This does not call the function. It's a comma expression that:
C's motto: who cares what it means? I just compile it!My own favorite in this vein is this:
Still not convinced? Try this one (suggested by Mark Scarbrough )
char *f() { char result[80]; sprintf(result,"anything will do"); return(result); /* Oops! resultis 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 acorrect program; As long as nothing has reused the particular piece ofstack occupied by result. Even within a single expression, even with only strictly manifestside effects, C doesn't define the order of the side effects.Therefore, depending on your compiler, I/++I might be either 0 or 1.Try this:
Prints either "Foo got 2", or "Bar got 2" Actually, this bug is so well known, it didn't even make the list!That doesn't make it less deadly when it strikes. Consider the simplestcase:
and in truth, modern compilers will usually flag an error as blatant asthe above. However, you just have to be a little more clever tooutsmartthe compiler. Consider:
The compile-time environment of a typical compilation is clutteredwith hundreds (or thousands!) of things that you typically have littleor no awareness of. These things sometimes have dangerouslycommon names, leading to accidents that can be virtually impossible tospot. #include #define BUFFSIZE 2048 longfoo[BUFSIZ]; //notespellingofBUFSIZ != BUFFSIZE This compiles without error, but will fail in predictably awfuland mysterious ways, because BUFSIZ is a symbol defined bystdio.h. A typo/braino like this can be virtually impossible tofind if the distance between the the #define and the error is greaterthan in this trivial example. I've been seriously burned because different compilers, or evendifferent options of the same compiler, define the fundamental type int aseither 16 or 32 bits.. In the same vein, name any other languagein which boolean might be defined or undefined, or might bedefined by a compiler option, a runtime pragma (yes! we havebooleans!), or just about any way the user decided would work ok. This is so obvious it didn't even make the list for the first 5years, but C's arrays and associated memory management are completely,utterly unsafe, and even obvious cases of 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,andno one cares */ } Of course, there are infinitely many ways to do things like thisin C. Read more: http://technicalstudies.youngester.com/2012/01/get-screwed-with-c-programming.html |



