This is a well know case that is documented in Code Complete which recently resurfaced in comp.lang.asm.x86 and rec.games.programmer. A developer is trying to write a small library of routines in which he includes:
void CopyBytes(char * pSrc, char * pDst, unsigned int Len) { for( ; Len != 0 ; Len--, pDst++, pSrc++ ) { *pDst = *pSrc; } } |
And, being the good programmer that he is, he decides to build on what he has already accomplished by including the following function:
void ByteFill(char Src, char * pDst, unsigned int Len) { if( Len>0 ) { *pDst = Src; CopyBytes( pDst, pDst + 1, Len-1 ); } } |
Notice the rather devious trick used here. While its probably not the best in terms of performance, he saves on code space and increases reliability by using previously "proven" functions. His library, including these routines, works just fine. Then he decides its time for optimizations. The word size on his computer is 2 bytes, so he rewrites the CopyBytes as follows:
/* The size factor, SF, should be 2 */ #define SF (sizeof(int)/sizeof(char)) assert( SF*sizeof(char) == sizeof(int) ); void CopyBytes(char * pSrc, char * pDst, unsigned int Len) { for( ; (Len % SF) != 0 ; Len--, pSrc++, pDst++ ) { * pDst = * pSrc; } for( ; Len != 0; Len -= SF, pDst += SF, pSrc += SF ) { *(int *)pDst = *(int *)pSrc; } } |
After a few minutes of analysis he convinces himself that what he has written is good and should yield improved performance. But as a side effect, of course, he has broken his ByteFill function. (If you don't see it go over it again and try to see why.)
This is a very difficult case. Because its very hard to see what has gone wrong without actual hands on debugging of the failed ByteFill function. The programmers cleverness bit him in the butt. For a more thorough discussion of this case study I refer you to Code Complete from Microsoft press. For a related discussion see "Block Copy".