[comp.std.c] Declarations in switches, errors

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (09/27/89)

In the process of looking for a totally diferent problem, I generated
the following program:

main() {
 int i = 2;
 switch (i) {
  int j = 4;
 case 1: j += 4; break;
 case 2:
 case 3:
 case 'a':
 case 'b':
  j--; break;
 }
}

Note the initialization in the 4th statement. I was unable to find any
compiler which generated working code for this initialization (although
one did complain that the code was not reached). I tried Sun, Ultrix,
Xenix and gcc compilers.

This is an error in the compilers! As ugly as this is, the ANSI standard
(3.1.2.4) says "If an initialization is specified for the value stored
in the object, it is performed on each normal entry, but not if the
block is entered by a jump to a label."

I submit that executing a switch statement constitutes "normal entry"
and that the initialization should be performed before evaluating the
switch variable. Would any of the people still on X3J11 like to comment?

Please let's not discuss the merits (or beauty) of this technique.
Although I was in an attempt to find another compiler error, I can
think of a few places where functional initialization would actually be
useful.

-- 
bill davidsen	(davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen)
"The world is filled with fools. They blindly follow their so-called
'reason' in the face of the church and common sense. Any fool can see
that the world is flat!" - anon

kremer@cs.odu.edu (Lloyd Kremer) (09/28/89)

In article <561@crdos1.crd.ge.COM> davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr)writes:

>main() {
>  int i = 2;
>  switch (i) {
>  int j = 4;
>  case 1: j += 4; break;
>  case 2:
>  case 3:
>  case 'a':
>  case 'b':
>  j--; break;
>  }
>}
>
>Note the initialization in the 4th statement. I was unable to find any
>compiler which generated working code for this initialization (although
>one did complain that the code was not reached). I tried Sun, Ultrix,
>Xenix and gcc compilers.
>
>This is an error in the compilers! As ugly as this is, the ANSI standard
>(3.1.2.4) says "If an initialization is specified for the value stored
>in the object, it is performed on each normal entry, but not if the
>block is entered by a jump to a label."
>
>I submit that executing a switch statement constitutes "normal entry"


No, a switch statement is entered by a jump to a label.  The jump is to
any one of several places depending on which "case" is true, but an automatic
initialization at the start of a switch statement is never performed.  The
variable is brought into scope within the switch block, but the initial
contents of the variable are garbage.

-- 
					Lloyd Kremer
					...!uunet!xanth!kremer
					Have terminal...will hack!

cpcahil@virtech.UUCP (Conor P. Cahill) (09/28/89)

In article <10041@xanth.cs.odu.edu>, kremer@cs.odu.edu (Lloyd Kremer) writes:
> No, a switch statement is entered by a jump to a label.  The jump is to
> any one of several places depending on which "case" is true, but an automatic
> initialization at the start of a switch statement is never performed.  The
> variable is brought into scope within the switch block, but the initial
> contents of the variable are garbage.

If this is the standard, I think it is broken.  If the compiler allows 
a variable declaration, it should allow an initialization.








-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/28/89)

In article <561@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
>I submit that executing a switch statement constitutes "normal entry"
>and that the initialization should be performed before evaluating the
>switch variable. Would any of the people still on X3J11 like to comment?

No, the block is the controlled part of the switch and it is entered
via a case or default label, not sequentially starting at the block
beginning.  Declarations before the first label are valid, but no
auto initialization is performed since execution does not "plow
through" the declarations but instead bypasses them.

The above is my understanding of what is supposed to be going on in
a switch statement; my X3J11 notes are elsewhere at the moment.

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/28/89)

In article <1202@virtech.UUCP>, cpcahil@virtech.UUCP (Conor P. Cahill) writes:
> If this is the standard, I think it is broken.  If the compiler allows 
> a variable declaration, it should allow an initialization.

If I recall correctly (my copy of the Standard is not at hand), you can
specify the initializer but of course it won't be executed.  Consider
the following analogous case (which does NOT involve "switch") to see why:

	goto label;
	{
		int i = 4;
		foo();
	label:	bar();
		baz();
	}

dfp@cbnewsl.ATT.COM (david.f.prosser) (09/28/89)

In article <1202@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>In article <10041@xanth.cs.odu.edu>, kremer@cs.odu.edu (Lloyd Kremer) writes:
>> No, a switch statement is entered by a jump to a label.  The jump is to
>> any one of several places depending on which "case" is true, but an automatic
>> initialization at the start of a switch statement is never performed.  The
>> variable is brought into scope within the switch block, but the initial
>> contents of the variable are garbage.
>
>If this is the standard, I think it is broken.  If the compiler allows 
>a variable declaration, it should allow an initialization.

The pANS specifies the way the C language works.  Period.  A switch
statement is a multiway jump to a finite set of labels.  If you jump
into a block skipping over certain expressions, these expressions
will not be executed.  Similarly, if you skip over the code for
initialization, it will not be executed.  The allocation of automatic
objects is a slightly different matter, so at least the objects are
guaranteed to exist.

The following example is copied from the pANS, section 3.6.4.2:

	Example
	    In the artificial program fragment

		switch (expr)
		{
			int i = 4;
			f(i);
		case 0:
			i = 17;  /* falls through into default code */
		default:
			printf("%d\n", i);
		}

	the object whose identifier is i exists with automatic
	storage duration (within the block) but is never initialized,
	and thus if the controlling expression has a nonzero value,
	the call to the printf function will access an indeterminate
	value.  Similarly, the call to the function f cannot be
	reached.

There is nothing preventing a translator from warning that the code
will not be reached, but it cannot refuse to compile fragments such
as the above example.

Dave Prosser	...not an official X3J11 answer...

scjones@sdrc.UUCP (Larry Jones) (09/29/89)

In article <561@crdos1.crd.ge.COM>, davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) writes [edited]:
>  switch (i) {
>   int j = 4;   /* this initialization doesn't happen! */
>  case 1: j += 4; break;
>  case 2:
>  }
> 
> This is an error in the compilers! As ugly as this is, the ANSI standard
> (3.1.2.4) says "If an initialization is specified for the value stored
> in the object, it is performed on each normal entry, but not if the
> block is entered by a jump to a label."
> 
> I submit that executing a switch statement constitutes "normal entry"
> and that the initialization should be performed before evaluating the
> switch variable. Would any of the people still on X3J11 like to comment?

Sure!  If you look at Section 3.6.4.2 (The switch statement), you
will find that:

	A switch statement causes control to jump to, into, or
	past the statement that is the switch body, depending on
	the value of a controlling expression, and on the
	presence of a default label and the values of any case
	labels on or in the switch body.

Thus, a case statement is just a specialized form of goto and case
labels are just that -- labels.  You are not entering the body
normally, you are jumping into it.

Looking further in the same section shows an example which looks
remarkably like yours with the explaination that the variable
exists within the switch body, but is never initialized.
----
Larry Jones                         UUCP: uunet!sdrc!scjones
SDRC                                      scjones@SDRC.UU.NET
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150-2789             AT&T: (513) 576-2070
"I have plenty of good sense.  I just choose to ignore it."
-Calvin

cpcahil@virtech.UUCP (Conor P. Cahill) (09/29/89)

In article <11173@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> In article <1202@virtech.UUCP>, cpcahil@virtech.UUCP (Conor P. Cahill) writes:
> > If this is the standard, I think it is broken.  If the compiler allows 
> > a variable declaration, it should allow an initialization.
> If I recall correctly (my copy of the Standard is not at hand), you can
> specify the initializer but of course it won't be executed.  Consider
> the following analogous case (which does NOT involve "switch") to see why:
> 
> 	goto label;
> 	{
> 		int i = 4;
> 		foo();
> 	label:	bar();
> 		baz();
> 	}



I still don't agree with this.  One does not "conceptualize" the initialization
as an execution.  Since the code used to allocate the automatic variable on 
the stack is executed, the code used to initialize the variable should be
executed.

In addition the behavior is different if the declaration is "static int...".
In that case the initialization does take place.  What it the justification
for the different behavior?  



-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

diamond@csl.sony.co.jp (Norman Diamond) (09/29/89)

In article <561@crdos1.crd.ge.COM> davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr)writes:

>>I submit that executing a switch statement constitutes "normal entry"

In article <10041@xanth.cs.odu.edu> kremer@cs.odu.edu (Lloyd Kremer) writes:

>No, a switch statement is entered by a jump to a label.

Mr. Kremer, you start your reply with "No."  So you think that correct
execution of a switch statement constitutes abnormal entry to the block.
I conjecture that very few will agree with you.

Otherwise, it seems that both posters are correct.  Executing a switch
statement is both normal entry and a jump to a label.  The standard is
self-contradictory.

-- 
Norman Diamond, Sony Corporation (diamond@ws.sony.junet)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

bill@twwells.com (T. William Wells) (09/29/89)

In article <561@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
: In the process of looking for a totally diferent problem, I generated
: the following program:
:
: main() {
:  int i = 2;
:  switch (i) {
:   int j = 4;
:  case 1: j += 4; break;
:  case 2:
:  case 3:
:  case 'a':
:  case 'b':
:   j--; break;
:  }
: }
:
: Note the initialization in the 4th statement. I was unable to find any
: compiler which generated working code for this initialization (although
: one did complain that the code was not reached). I tried Sun, Ultrix,
: Xenix and gcc compilers.
:
: This is an error in the compilers! As ugly as this is, the ANSI standard
: (3.1.2.4) says "If an initialization is specified for the value stored
: in the object, it is performed on each normal entry, but not if the
: block is entered by a jump to a label."
:
: I submit that executing a switch statement constitutes "normal entry"
: and that the initialization should be performed before evaluating the
: switch variable.

dpANS 3.6.1:

"labeled-statement:
	identifier : statement
	case constant-expression : statement
	default : statement"

Case and default are *labels*.

dpANS 3.6.4.2:

"A switch statement causes control to *jump* to, into, or past..."
(Italics mine.)

Also, I believe that K&R explicitly says that this won't work.

---
Bill                    { uunet | novavax | ankh | sunvice } !twwells!bill
bill@twwells.com

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (09/29/89)

I guess my main thought on declarations at the start of a switch is that
anything which is allowed (ie. legal C) should work. It would probably
take less effort to make it work than to add error checking code, from a
compiler standpoint.

It a feature with limited use even if it did work, but I am bothered by
anything I can write which is legal but may not work the same way on all
implementations. Perhaps a little matter for the next committee would be
to either say "initialization of variables declared at the start of a
switch is not allowed" or "variables declared at the beginning of a
switch are initialized before the control expression is evaluated, even
if no cases are matched."

I have no strong feelings about whether it should or shouldn't work, but
it should be predictable. That's what standards are all about, right?

-- 
bill davidsen	(davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen)
"The world is filled with fools. They blindly follow their so-called
'reason' in the face of the church and common sense. Any fool can see
that the world is flat!" - anon

henry@utzoo.uucp (Henry Spencer) (09/30/89)

In article <561@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
> switch (i) {
>  int j = 4;
> case 1: /* ... */
>
>Note the initialization in the 4th statement. I was unable to find any
>compiler which generated working code for this initialization...
>(3.1.2.4) says "If an initialization is specified for the value stored
>in the object, it is performed on each normal entry, but not if the
>block is entered by a jump to a label."
>I submit that executing a switch statement constitutes "normal entry"...

Sorry, wrong.  3.6.4.2:  "...control jumps to the statement following
the matched case label..."  Also note the example in 3.6.4.2, which
explicitly makes the point that initializers in such a context are
not executed.
-- 
"Where is D.D. Harriman now,   |     Henry Spencer at U of Toronto Zoology
when we really *need* him?"    | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

walter@hpclwjm.HP.COM (Walter Murray) (09/30/89)

Concerning initialization of variables in a switch statement, please
note that the dpANS only repeats what was spelled out in the original
K&R:

   "Usually the statement that is the subject of a switch is
   compound.  Declarations may appear at the head of this statement,
   but initializations of automatic or register variables are
   ineffective."  Page 203.

And the dpANS document does suggest this as a common situation for a
warning:

   "A block with initialization of an object that has automatic
   storage duration is jumped into."  Section A.5.

Walter Murray
-------------

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/30/89)

In article <1211@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>One does not "conceptualize" the initialization as an execution.

Then one has the wrong mental model.  Auto initialization is to all extents
and purposes execution of an assignment statement.  It therefore differs
radically from static initialization, which is what your model fits.

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/30/89)

In article <637@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
>I have no strong feelings about whether it should or shouldn't work, but
>it should be predictable. That's what standards are all about, right?

The Standard specifies precisely what happens here.  It is not
implementation-dependent.

henry@utzoo.uucp (Henry Spencer) (09/30/89)

In article <637@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
>It a feature with limited use even if it did work, but I am bothered by
>anything I can write which is legal but may not work the same way on all
>implementations...

If you want all legal constructs to work the same way in all implementations,
you are in the wrong newsgroup! :-)  C is *full* of things that are
implementation-specific to some degree or other.  The usual reason is
that most programs don't care about characteristic X, but want the code
to run fast, and pinning down characteristic X implies major speed loss
on some machines.

Actually, very few languages have the property you're after.  At the
very least, the detailed properties of floating-point arithmetic are
almost always implementation-defined.

And, as Doug has pointed out, ironically, the behavior of initializers at
the head of a case is not an example of this sort of thing.  Such
initializers *do* *not* get executed in any conforming implementation.
-- 
"Where is D.D. Harriman now,   |     Henry Spencer at U of Toronto Zoology
when we really *need* him?"    | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

ok@cs.mu.oz.au (Richard O'Keefe) (09/30/89)

In article <561@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
: In the process of looking for a totally diferent problem, I generated
: the following program:
: main() {
:  int i = 2;
:  switch (i) {
:   int j = 4;
:  case 1: j += 4; break;
[much deleted]

C has *always* worked like this.  The body of a switch is a statement
and the switch is a jump.  Here's a really ugly piece of code I wrote
to illustrate this once:
    main(argc)
	{
	    switch (argc)
		if (0) case 1: printf("1\n");
                else if (0) default: printf("not 1\n");
		else printf("impossible\n");
	    exit(0);
	}
"gcc -ansi -pedantic" still likes it!  If you want initialised declarations,
put the switch inside the block instead of the block inside the switch.
A good C compiler ought to print a warning message about initialised
declarations in a switch() body, but that's "quality of implementation".

barmar@kulla (Barry Margolin) (10/01/89)

In article <1989Sep30.052000.13719@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes:
>And, as Doug has pointed out, ironically, the behavior of initializers at
>the head of a case is not an example of this sort of thing.  Such
>initializers *do* *not* get executed in any conforming implementation.

Well, since the initial value of automatic variables is undefined, a
conforming implementation COULD execute them.  A strictly conforming
program cannot take advantage of this, though.

Here's something I think is closer to the original poster's complaint:
why does the standard permit initializers in declarations at the head
of a switch body, if they are required to be ignored?  If they were
disallowed, then user's wouldn't be tempted to think they would be
executed.

The original poster postulated that it should be easy for
implementations to initialize these variables, since it must allocate
space for them.  As was mentioned by several people in a different
chain (which might have been in comp.lang.c), many C compilers
allocate space for all the auto variables in a function when the
function is entered; no actual allocation and deallocation takes place
when entering and exiting internal blocks (this is possible because C
doesn't allow variable-sized automatic arrays).  Therefore, jumping to
a label inside a block doesn't have to do any allocation.  Thus, a
compiler can treat a variable declaration with an initializer as if
the declaration without the initializer were located in the outermost
block (this is a simplification, as it ignores name conflicts) and the
initializer were just an assignment statement.
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

blarson@basil.usc.edu (bob larson) (10/01/89)

>In article <1989Sep30.052000.13719@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes:
>>Such
>>initializers *do* *not* get executed in any conforming implementation.

In article <30540@news.Think.COM> barmar@kulla (Barry Margolin) writes:
>Well, since the initial value of automatic variables is undefined, a
>conforming implementation COULD execute them.  

It COULD NOT execute any of the side effects the initializers have, however.
A compiler that recognises this case should IMHO just give a warning.

I have ported megabytes of net code to a machine that does not generate
correct code for any declarations in a switch statement block, (code to
adjust the stack is generated where it is never executed) and have found
only one program where this is a problem.  (C-kermit, the current beta
has this fixed.)

--
Bob Larson	Arpa:	blarson@basil.usc.edu
Uucp: usc!basil!blarson

henry@utzoo.uucp (Henry Spencer) (10/01/89)

In article <30540@news.Think.COM> barmar@kulla (Barry Margolin) writes:
>...why does the standard permit initializers in declarations at the head
>of a switch body, if they are required to be ignored?  ...

In fact, one can read the C++ Reference Manual (as of Stroustrup's book --
haven't seen the latest one) as forbidding such initializers.  While the
section on switch has the same old C wording, the section on goto is quite
firm that jumping past an initializer is forbidden.
-- 
"Where is D.D. Harriman now,   |     Henry Spencer at U of Toronto Zoology
when we really *need* him?"    | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/01/89)

In article <30540@news.Think.COM> barmar@kulla (Barry Margolin) writes:
>Well, since the initial value of automatic variables is undefined, a
>conforming implementation COULD execute them.

NO, not in general.  (The only time it could occur is if it would
have no observable effect!  What would be the point of that?)

>why does the standard permit initializers in declarations at the head
>of a switch body, if they are required to be ignored?

Because it's attempting to standardize C, not some vaguely similar
language.

The initializer IS NOT REQUIRED TO BE IGNORED.  It is treated
EXACTLY like any other auto initializer.  Static initializers
in a switch body are also treated like any other static initializers.

You guys have the wrong mental model of C initialization!

chris@mimsy.UUCP (Chris Torek) (10/01/89)

In article <30540@news.Think.COM> barmar@kulla (Barry Margolin) writes:
>Here's something I think is closer to the original poster's complaint:
>why does the standard permit initializers in declarations at the head
>of a switch body, if they are required to be ignored?

It makes the language simpler conceptually: all variable declarations
are of the form

    <type> <var> <optional initialiser> [, <var> <optional initialiser>]* ;

Even a compiler that is only 1/3 decent% will warn about unreachable
initialisers.

Note that the <optional initialiser>s are, as Doug has already pointed
out (it seems to require a great deal of repetition to get these to sink
in), treated as though they were executable statements when they apply
to automatic (as opposed to static or global) variables.
-----
% 1/3: `less than half'
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

ok@cs.mu.oz.au (Richard O'Keefe) (10/01/89)

In article <19907@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> Even a compiler that is only 1/3 decent% will warn about unreachable
> initialisers.

I tried the following program (laid out to fit in two lines):
	main(argc) int argc; { switch (argc) { int i = 1; double x = 2.0;
        case 1: case 2: exit(i); default: exit(!!x); }}
On a Sun-3/50 running SunOS 4.0.something
	cc:	"line 1: warning: statement not reached"
	CC:	"warning:  statement not reached: case label missing"
	lint:	"(1): warning: statement not reached"
	gcc:	/* silence */
	gcc -W:	/* silence */

I suppose you *could* call this warning about unreachable initialisers,
but calling them unreachable *statements* seems a little unhelpful.
CC's message makes sense because C++ *would* allow a case label before
the declarations (so the initialisers would be done sometimes!).

Do I have permission to call gcc indecent now? 

lawley@cs.mu.OZ.AU (michael lawley) (10/02/89)

On 1 Oct 89 14:32:00 GMT,
ok@cs.mu.oz.au (Richard O'Keefe) said:

> In article <19907@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
>> Even a compiler that is only 1/3 decent% will warn about unreachable
>> initialisers.

> I tried the following program (laid out to fit in two lines):
> 	main(argc) int argc; { switch (argc) { int i = 1; double x = 2.0;
>         case 1: case 2: exit(i); default: exit(!!x); }}
> On a Sun-3/50 running SunOS 4.0.something
> 	cc:	"line 1: warning: statement not reached"
> 	CC:	"warning:  statement not reached: case label missing"
> 	lint:	"(1): warning: statement not reached"
> 	gcc:	/* silence */
> 	gcc -W:	/* silence */

I just ran the same code through "gcc -Wall -O".  The -O causes gcc to do
dataflow analysis etc. which it would otherwise not do.  Here is the output:

tt.c: In function main:
tt.c:1: warning: return-type defaults to `int'
tt.c:2: warning: implicit declaration of function `exit'
tt.c:1: warning: `i' may be used uninitialized in this function
tt.c:1: warning: `x' may be used uninitialized in this function
tt.c:2: warning: control reaches end of non-void function

Running with just "gcc -W -O" (for those of you who like sloppy code) gives

tt.c: In function main:
tt.c:1: warning: `i' may be used uninitialized in this function
tt.c:1: warning: `x' may be used uninitialized in this function

> I suppose you *could* call this warning about unreachable initialisers,
> but calling them unreachable *statements* seems a little unhelpful.
> CC's message makes sense because C++ *would* allow a case label before
> the declarations (so the initialisers would be done sometimes!).

These would seem to me to be much more useful error messages than the other
compilers produce.

> Do I have permission to call gcc indecent now? 

What about now?

karzes@mfci.UUCP (Tom Karzes) (10/03/89)

In article <561@crdos1.crd.ge.COM> davidsen@crdos1.UUCP (bill davidsen) writes:
-This is an error in the compilers! As ugly as this is, the ANSI standard
-(3.1.2.4) says "If an initialization is specified for the value stored
-in the object, it is performed on each normal entry, but not if the
-block is entered by a jump to a label."

Switching into a block via a switch statement clearly consitutes entering
the block by a jump to a label.  No code between the beginning of the block
and the case label should be executed, including dynamic initializations of
any automatic variables declared in the block.

msb@sq.sq.com (Mark Brader) (10/04/89)

Actually, there *is* a way to "normally enter" the switch body.
Instead of entering the body by a jump from the switch header, you
put a label on the body itself and jump to that!

	main() {
		int k = 0, m = 0;
		switch (m) bleagh: {
			int j = 4;
		case 0:
			printf ("%d\n", j);
		}
		if (k++ == 0)
			goto bleagh;
	}

Assuming that the implementation doesn't trap on undefined values,
this prints a garbage integer value, then 4.  It would never have
occurred to me to try this, if not for this discussion stream, and I
can't dream of a sensible use for it.  Isn't C wonderful?

Only slightly less bizarre is to put one of the case labels ON the
switch body rather than IN it -- 3.6.4.2 allows this and the compilers
we have here support it -- whereupon you get initialization IF it is
the first case that is chosen.  For instance:

	initj() {printf ("initj() called\n"); return 4;}
	main() {
		int k;
		for (k = 0; k < 3; ++k)
			switch (k)
			case 1:
				{
				int j = initj();
			default:
				printf ("%d\n", j);
			}
	}

Assuming that the implementation doesn't trap on undefined values,
this prints a garbage integer value, "initj() called", 4, and another
garbage integer value.

-- 
Mark Brader		   "I don't care HOW you format   char c; while ((c =
SoftQuad Inc., Toronto	    getchar()) != EOF) putchar(c);   ... this code is a
utzoo!sq!msb, msb@sq.com    bug waiting to happen from the outset." --Doug Gwyn

This article is in the public domain.

karzes@mfci.UUCP (Tom Karzes) (10/05/89)

In article <1989Oct3.184849.20106@sq.sq.com> msb@sq.com (Mark Brader) writes:
>Actually, there *is* a way to "normally enter" the switch body.
>Instead of entering the body by a jump from the switch header, you
>put a label on the body itself and jump to that!
>...
>Only slightly less bizarre is to put one of the case labels ON the
>switch body rather than IN it -- 3.6.4.2 allows this and the compilers
>we have here support it -- whereupon you get initialization IF it is
>the first case that is chosen.

Note that although normal switch statement usage almost always involves
a compound statement with all case labels at the top level within the
compound statement, the syntax actually allows any statement.  For example,
the following:

    switch (x)
        case 5: case 9: foo();

if equivalent to:

    if ((t = x) == 5 || t == 9)
        foo();

where t is some temporary to avoid evaluating x more than once.

Similarly, one might have:

    switch (x)
        case 2: if (y)
        default:    foo();
                else
        case 7:     while (bar(z)) {
        case 12:        baz();
        case 13:        z++;
                    }

Again, I'm not advocating any of this, I'm merely pointing out that it's
within the definition of the language.

flaps@dgp.toronto.edu (Alan J Rosenthal) (10/13/89)

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) writes:
>>>I submit that executing a switch statement constitutes "normal entry"

kremer@cs.odu.edu (Lloyd Kremer) writes:
>>No, a switch statement is entered by a jump to a label.

diamond@csl.sony.co.jp (Norman Diamond) writes:
>Mr. Kremer, you start your reply with "No."  So you think that correct
>execution of a switch statement constitutes abnormal entry to the block.
>I conjecture that very few will agree with you.

A point generally being missed in this discussion is that "normal entry" is a
precise term.  It is not just whatever method you personally usually choose to
enter a block with a particular wrapper.  It is the method of entering a block
in general which is called "normal entry" by the standard.  I can't find a
definition of "normal entry", but I do find the following, 3.1.2.4, January
1988 draft:

	... automatic storage duration.  Storage is guaranteed to be reserved
	for a new instance of such an object on each normal entry into the
	block in which it is declared, or on a jump from outside the block to a
	label in the block or in an enclosed block.  If an initialization is
	specified for the value stored in the object, it is performed on each
	normal entry, but not if the block is entered by a jump to a label.

I think this is extremely clear.

ajr

--
Vs encr vf n xvaq bs frk, gura n chapu va gur zbhgu vf n xvaq bs gnyxvat.

karl@haddock.ima.isc.com (Karl Heuer) (10/13/89)

In article <10888@riks.csl.sony.co.jp> diamond@riks. (Norman Diamond) writes:
>Mr. Kremer [seems to] think that correct execution of a switch statement
>constitutes abnormal entry to the block.  I conjecture that very few will
>agree with you.

I agree with him.  `Normal' entry to a block is by falling into it from above.
A block that happens to be the body of a switch is entered abnormally.  This
is not a contradiction.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

karzes@mfci.UUCP (Tom Karzes) (10/13/89)

In article <10888@riks.csl.sony.co.jp> diamond@riks. (Norman Diamond) writes:
->>I submit that executing a switch statement constitutes "normal entry"
->No, a switch statement is entered by a jump to a label.
-
-Mr. Kremer, you start your reply with "No."  So you think that correct
-execution of a switch statement constitutes abnormal entry to the block.
-I conjecture that very few will agree with you.
-
-Otherwise, it seems that both posters are correct.  Executing a switch
-statement is both normal entry and a jump to a label.  The standard is
-self-contradictory.

For Pete's sake, this silly discussion was resolved long ago.  Let it die.
The answer is very simple; you just don't like it.  A switch statement
in C takes a single subordinate statement.  It can be ANY statement.  Any
case or default labels within that statement which are not associated with
a more closely nested switch statement are associated with that switch
statement.  That's ALL you need to know to figure out the rest.  Typical
use of a switch statement (and indeed the only use with which most people
are familiar) is to use a block as the subordinate statement, with all
case labels, and the default label (if present), at the top level inside
the block.  In this case, execution of the switch statement causes a branch
into the block in the non-fall-through case, therefore the block is NOT
entered "normally" and any automatic initializations contained within
that block will be skipped.  To do otherwise would be extremely unintuitive.
All kinds of special exceptions about entering blocks via a switch statement
would have to be added, and the implementation would be dreadful.  If no
default label was present, the compiler would first have to evaluate the
expression and determine whether it matched one of the case labels.  If
so, it would then have to branch to the start of the block and execute any
automatic initializations.  Then it would have to actually branch to
the appropriate case label.  It's an absurd proposal, and is extremely
unintuitive to anyone with even an average grasp of C.  When I first
learned C many years ago, I didn't initially realize that switch
statements could take any type of subordinate statement, and in particular
that the subordinate statement could be a block that contained declarations,
some of which might be automatics with initializers.  When I did learn about
this, it was OBVIOUS that executing the switch statement would blow right
past any such initializers.  Perhaps what you really don't like is the
term "normal entry", because "abnormal entry" is somehow "bad", which
implies that typical use of a switch statement is "bad".  Fine.  Think of
it as "fall-through entry", or "normal-but-non-switch entry", or whatever
pedagogical aid seems appropriate to you.  No one ever claimed that C was
an easy language for beginners.  And please post any further speculation
as to how switch statements ought to be redesigned to comp.lang.misc.
The members of the ANSI committee weren't total morons, you know.

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/14/89)

In article <10888@riks.csl.sony.co.jp> diamond@riks. (Norman Diamond) writes:
>Mr. Kremer, you start your reply with "No."  So you think that correct
>execution of a switch statement constitutes abnormal entry to the block.
>I conjecture that very few will agree with you.

You lose, then.  The only use of the term "normal entry into a block" I
could find in the Standard is in 3.1.2.4, where it is contrasted to a
"jump from outside the block to a labeled statement in the block or in
an enclosed block".  The description of "switch" in 3.6.4.2 is quite
explicit that a jump occurs, and that "case" and "default" are labels.

diamond@csl.sony.co.jp (Norman Diamond) (10/16/89)

Regarding the old, dead topic:

>>>I submit that executing a switch statement constitutes "normal entry"
>>No, a switch statement is entered by a jump to a label.
>execution of a switch statement constitutes abnormal entry to the block.

In article <1079@m3.mfci.UUCP> karzes@mfci.UUCP (Tom Karzes) writes:

>For Pete's sake, this silly discussion was resolved long ago.  Let it die.

Yes.  It died about two weeks after I submitted my posting.

Last week I re-submitted five questions about the preprocessor.  I thought
that the original postings had gotten lost (a few weeks ago) in the maze of
one little twisty news passage through kddlabs to the rest of the world.

Before you criticize a poster for beating an old topic, why don't you
look to see how long ago the submission was actually written?

-- 
Norman Diamond, Sony Corp. (diamond%ws.sony.junet@uunet.uu.net seems to work)
  Should the preceding opinions be caught or     |  James Bond asked his
  killed, the sender will disavow all knowledge  |  ATT rep for a source
  of their activities or whereabouts.            |  licence to "kill".