Path: utzoo!utgpu!water!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!cwjcc!gatech!uflorida!novavax!proxftl!bill From: bill@proxftl.UUCP (T. William Wells) Newsgroups: comp.lang.c Subject: Re: Explanation, please! Message-ID: <634@proxftl.UUCP> Date: 27 Aug 88 14:55:24 GMT References: <638@paris.ICS.UCI.EDU> Reply-To: bill@proxftl.UUCP (T. William Wells) Organization: Proximity Technology, Ft. Lauderdale Lines: 129 Summary: Expires: Sender: Followup-To: Distribution: Keywords: In article <638@paris.ICS.UCI.EDU> schmidt@bonnie.ics.uci.edu (Douglas C. Schmidt) writes: : The following piece of wonderful obscurity comes from Stroustup's : C++ Programming Language book, page 100: : : void send(int *to,int *from, int count) { : int n = (count + 7) / 8; : : switch(count % 8) { : case 0: do { *to++ = *from++; : case 7: *to++ = *from++; : case 6: *to++ = *from++; : case 5: *to++ = *from++; : case 4: *to++ = *from++; : case 3: *to++ = *from++; : case 2: *to++ = *from++; : case 1: *to++ = *from++; : } while (--n > 0); : } : : } : : Now, much to my surprise, this is not only valid C++, it is also valid C! : Could some one please explain to me why this is so? It seems like : the case 7-1 labels are actually nested inside the do {} while loop, : and thus not in the scope of the switch (should a break statement exit : both the switch and the loop, or just one?!?!). A switch statement has the syntax switch () While it is conventional to use a compound statement as the embedded statement, there is nothing requiring it. What a switch does is permit the definition of a set of labels within the statement, to which control is passed by the head of the switch. The exclusive use of compound statements is not only conventional coding practice, it is also good coding practice. : Finally, Stroustrup asks the rhetorical question ``why would anyone : want to write something like this.'' Any guesses?! The false god of efficiency has reared it ugly head. This routine would be imagined to be more efficient than the almost equivalent: void send( int *to, int *from, int count) { if (count <= 0) { create progam bug } while (--count >= 0) { *to++ = *from++; } } However, it often (always?) is not. Consider a machine which has a fast means of moving small blocks of memory. The following routine should do the same thing (without the bug, of course), might be more efficient, and is more understandable as well. Of course, it might generate a smidgin more code, but I think that, in this case, this is a small price to pay. void send( int *to, int *from, int count) { if (count <= 0) { return; } switch (count % 7) { case 7: *to++ = *from++; case 6: *to++ = *from++; case 5: *to++ = *from++; case 4: *to++ = *from++; case 3: *to++ = *from++; case 2: *to++ = *from++; case 1: *to++ = *from++; } count >>= 3; while (--count >= 0) { *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; } } However, at least two IBM-PC compilers ought to generate better code from the "unoptimized" version. (Actually, they do it if the copied items are characters; I presume that they'll do it for integers.) I wouldn't be surprised if other compilers did as well. void send( int *to, int *from, int count) { /* If you are really paranoid, add the following code, it catches the case where count is minus full scale on a two's complement machine. I tend to not do this, since I consider minus full scale to be an illegal value and take the minimal pains needed to never generate it. if (count <= 0) { return; } */ while (--count >= 0) { *to++ = *from++; } } --- Bill novavax!proxftl!bill