Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Aquis

macrumors member
Original poster
Aug 7, 2007
63
0
Staffordshire, UK
I have a fairly simple switch statement which gives a syntax error if I try to create an object in it:
Code:
	int number = 0;
	switch (number) {
		case 0:
			NSObject * object = [[NSObject alloc] init];
			break;
		default:
			break;
	}
Yes, I realise that NSObject's don't do anything and yes, there's no point because I know for sure what number is at that point—it's just for an example. But I get a syntax error (error before * token) on the line where I create the object, and no matter what Objective-C object it is, it always creates an error. Why is this? Thanks!

Oh, and it's definitely aware of NSObject, I can just put in the same line without the switch statement no problem.
 

iSee

macrumors 68040
Oct 25, 2004
3,539
272
The problem is that the code declares a variable in a case block.
C doesn't like that. I suppose it's because of the ambiguities that arise. For example, what happens with object if the switch statement jumps to the default block.

You can resolve this by putting the case statements in a statement block:
Code:
	int number = 0;
	switch (number) {
		case 0:
			{
				NSObject * object = [[NSObject alloc] init];
			}
			break;
		default:
			break;
	}
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
I have a fairly simple switch statement which gives a syntax error if I try to create an object in it:
Code:
	int number = 0;
	switch (number) {
		case 0:
			NSObject * object = [[NSObject alloc] init];
			break;
		default:
			break;
	}
Yes, I realise that NSObject's don't do anything and yes, there's no point because I know for sure what number is at that point—it's just for an example. But I get a syntax error (error before * token) on the line where I create the object, and no matter what Objective-C object it is, it always creates an error. Why is this? Thanks!

Oh, and it's definitely aware of NSObject, I can just put in the same line without the switch statement no problem.

Buy a good C book. Better yet, download a copy of the ISO C Standard document; you can get a free copy of the latest draft by typing "N1124" into Google. Once you have done that, have a look at the syntax for labeled statements. That should make things very clear. To demonstrate what you learned, you might post _why_ "case 0: ;" works and why "case 0:" doesn't work.
 

mdeh

macrumors 6502
Jan 3, 2009
345
2
[QUOTE
Yes, I realise that NSObject's don't do anything and yes, there's no point because I know for sure what number is at that point—it's just for an example. But I get a syntax error (error before * token) on the line where I create the object, and no matter what Objective-C object it is, it always creates an error. Why is this? Thanks!
[/QUOTE]

The expression following the keyword case must be an integral constant expression

ARM ( Harbison and Steele, V ed)
 

iSee

macrumors 68040
Oct 25, 2004
3,539
272
The expression following the keyword case must be an integral constant expression
ARM ( Harbison and Steele, V ed)

0 is the integral constant expression here, so that's not the problem.
 

mdeh

macrumors 6502
Jan 3, 2009
345
2
But do you know why? Why does "case 0:;" instead of "case 0:" work?

Well...afraid I am not sure what you are after.

Removing the statement works, placing it within it's own block works, doing what you suggests works. I assumed iSee's answer made sense. Not sure, but curious as to what you are getting at.
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
Well...afraid I am not sure what you are after.

Removing the statement works, placing it within it's own block works, doing what you suggests works. I assumed iSee's answer made sense. Not sure, but curious as to what you are getting at.

A label must be followed by a statement. The original poster followed the label by a declaration, which is not a statement. { int i = 0; } is a statement (compound statement). ";" on its own is an empty statement, the simplest of all statements. "int i = 0; " or something similar is not a statement, but a declaration.
 

iSee

macrumors 68040
Oct 25, 2004
3,539
272
I, too, don't understand what the "case 0:;" stuff is getting at.
I don't think this should work either :confused:
Code:
	int number = 0;
	switch (number) {
		case 0:;
			NSObject * object = [[NSObject alloc] init];
			break;
		default:
			break;
	}

I will probably give it a try, though, later and see what happens.

I thought that the C spec doesn't allow declaring variables where there is a mismatch between variable scope and flow control -- that is, it wants to prevent the situation where a program could jump over the declaration of a variable to a place where that variable is in scope. switch statements and gotos have this potential mismatch. while, do while and if statements do not have this potential. I'd be surprised if there was some way to trick out the compiler into allowing this after all. Live and learn, though!
 

mdeh

macrumors 6502
Jan 3, 2009
345
2
A label must be followed by a statement. The original poster followed the label by a declaration, which is not a statement. { int i = 0; } is a statement (compound statement). ";" on its own is an empty statement, the simplest of all statements. "int i = 0; " or something similar is not a statement, but a declaration.

Hi gnasher...yes, I see what you are saying. Just a small question. I thought that a statement like "int i = 0" is a definition and a declaration, but primarily a definition, in that the variable "i" has memory set aside for it, which is then assigned a value, in this case "0". Not sure if that changes anything you have said, though.
 

autorelease

macrumors regular
Oct 13, 2008
144
0
Achewood, CA
I, too, don't understand what the "case 0:;" stuff is getting at.
I don't think this should work either :confused:
Code:
	int number = 0;
	switch (number) {
		case 0:;
			NSObject * object = [[NSObject alloc] init];
			break;
		default:
			break;
	}

I will probably give it a try, though, later and see what happens.

I thought that the C spec doesn't allow declaring variables where there is a mismatch between variable scope and flow control -- that is, it wants to prevent the situation where a program could jump over the declaration of a variable to a place where that variable is in scope. switch statements and gotos have this potential mismatch. while, do while and if statements do not have this potential. I'd be surprised if there was some way to trick out the compiler into allowing this after all. Live and learn, though!

It works because:
1) a label must be immediately followed by a statement; declarations are not statements (see page 131 of the ISO spec)
2) a single ; is an acceptable statement, it just does nothing

I'm not 100% sure of the rationale behind not allowing a declaration to follow a label, but it might be something like this: A label assigns a name to the address in memory of an instruction. A declaration doesn't generate instructions in the typical manner (it tells the compiler how much stack space to allocate) so it's unclear what memory address you would associate with the label.

It doesn't have anything to do with scope. Variables can be declared anywhere else in a switch statement. For example, the following code compiles with no errors:
Code:
switch (a)
{
  int b = 9;
  case 0:
    printf("zero; b = %d\n", b);
    int c = 10;
    break;
  case 1:
    printf("one; b = %d, c = %d\n", b, c);
    int d = 11;
  default:
    printf("other; b = %d, c = %d, d = %d\n", b, c, d);
}

b, c, and d are all in scope; space for them has been allocated on the stack. However, b's value will be garbage because the switch statement jumps over its initializer. Likewise, if a = 1, c will be used uninitialized, and if a is neither 0 nor 1, then b, c, and d will be used uninitialized.

The only reason that something like
Code:
switch (a)
{
  case 0:
    int b = 9;
    // ...
}
doesn't work is because a label can only precede a statement, and declarations (even with initializers) are not statements. Likewise, this doesn't work either:
Code:
void myfunction()
{
  if (!do_stuff())
    goto mylabel;

mylabel:
  int i = 3;
  do_more_stuff();
}


The best way to declare variables in a case block is just to enclose the block in curly braces. While it's a nice trick, using lone semicolons leads to confusion (especially when used to indicate for/while loops with empty bodies)
 

iSee

macrumors 68040
Oct 25, 2004
3,539
272
It works because:
1) a label must be immediately followed by a statement; declarations are not statements (see page 131 of the ISO spec)
2) a single ; is an acceptable statement, it just does nothing

Yes, I see. It wasn't really the rule that a label must be followed by a statement rule that confused me. What I didn't understand is that it is legal to jump over a declaration. I looked in to this and found out where I went wrong. The actual rule, which I incorrectly remembered, is:

In C++, you can't jump over an initializer (i.e. a declaration where the variable is initialized with a value).

So I was wrong in 2 ways:

(1) I thought it was jumping over declarations, not initializers that was illegal.

(2) I thought this applied to C as well as C++. However in C it is perfectly OK to jump over both declarations and initializers (well, actually there are restrictions on jumping over the declarations of variable-length arrays and types based on variable-length arrays).

This all makes sense when I think about. In C++ it is very important that initializers be called -- that's part of the whole RAII thing. Skipping an initializer would mean you could have an object in scope that did not have a constructor called on it. So C++ has to be picker than C in order to support the RAII pattern.
 

lazydog

macrumors 6502a
Sep 3, 2005
709
6
Cramlington, UK
Hi

A trivial point but the Objective-C++ compiler does a much better job at compiling and picking up uninitialized variables in switch/case statements.
For example:-

Code:
switch ( i )
{
   case 0 :	int j = 1 ;
		break ;
			
   case 1 :	break ;
}

will generate a cross initialisation error, but

Code:
switch ( i )
{
   case 1 :	break ;

   case 0 :	int j = 1 ;
		break ;			
}

compiles fine.

b e n
 

autorelease

macrumors regular
Oct 13, 2008
144
0
Achewood, CA
(2) I thought this applied to C as well as C++. However in C it is perfectly OK to jump over both declarations and initializers (well, actually there are restrictions on jumping over the declarations of variable-length arrays and types based on variable-length arrays).

This all makes sense when I think about. In C++ it is very important that initializers be called -- that's part of the whole RAII thing. Skipping an initializer would mean you could have an object in scope that did not have a constructor called on it. So C++ has to be picker than C in order to support the RAII pattern.

Exactly. The little differences between C++ and C still trip me up quite frequently. :)
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.