Explanation, please!

T. William Wells bill at proxftl.UUCP
Sun Aug 28 00:55:24 AEST 1988


In article <638 at paris.ICS.UCI.EDU> schmidt at 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 (<expression>) <statement>

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



More information about the Comp.lang.c mailing list