Register FAQ / Rules Forum Spy Search Today's Posts Mark Forums Read
Go Back   MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old Apr 3, 2009, 06:16 AM   #1
Aquis
macrumors member
 
Join Date: Aug 2007
Location: Staffordshire, UK
Send a message via ICQ to Aquis Send a message via AIM to Aquis Send a message via MSN to Aquis Send a message via Yahoo to Aquis Send a message via Skype™ to Aquis
Why doesn't this switch statement work...

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.
__________________
15" MacBook Pro 2.8GHz
Aquis is offline   0 Reply With Quote
Old Apr 3, 2009, 06:48 AM   #2
iSee
macrumors 68030
 
iSee's Avatar
 
Join Date: Oct 2004
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;
	}
iSee is offline   0 Reply With Quote
Old Apr 3, 2009, 06:59 AM   #3
gnasher729
macrumors G5
 
gnasher729's Avatar
 
Join Date: Nov 2005
Quote:
Originally Posted by Aquis View Post
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.
gnasher729 is offline   0 Reply With Quote
Old Apr 3, 2009, 07:31 AM   #4
mdeh
macrumors 6502
 
Join Date: Jan 2009
[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]

Quote:
The expression following the keyword case must be an integral constant expression
ARM ( Harbison and Steele, V ed)
mdeh is offline   0 Reply With Quote
Old Apr 3, 2009, 08:09 AM   #5
iSee
macrumors 68030
 
iSee's Avatar
 
Join Date: Oct 2004
Quote:
Originally Posted by mdeh View Post
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.
iSee is offline   0 Reply With Quote
Old Apr 3, 2009, 09:21 AM   #6
mdeh
macrumors 6502
 
Join Date: Jan 2009
Quote:
Originally Posted by iSee View Post
0 is the integral constant expression here, so that's not the problem.
Stand corrected! Your solution does the trick
mdeh is offline   0 Reply With Quote
Old Apr 3, 2009, 12:54 PM   #7
gnasher729
macrumors G5
 
gnasher729's Avatar
 
Join Date: Nov 2005
Quote:
Originally Posted by mdeh View Post
Stand corrected! Your solution does the trick
But do you know why? Why does "case 0:;" instead of "case 0:" work?
gnasher729 is offline   0 Reply With Quote
Old Apr 3, 2009, 02:02 PM   #8
mdeh
macrumors 6502
 
Join Date: Jan 2009
Quote:
Originally Posted by gnasher729 View Post
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.
mdeh is offline   0 Reply With Quote
Old Apr 3, 2009, 03:28 PM   #9
gnasher729
macrumors G5
 
gnasher729's Avatar
 
Join Date: Nov 2005
Quote:
Originally Posted by mdeh View Post
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.
gnasher729 is offline   0 Reply With Quote
Old Apr 3, 2009, 03:29 PM   #10
iSee
macrumors 68030
 
iSee's Avatar
 
Join Date: Oct 2004
I, too, don't understand what the "case 0:;" stuff is getting at.
I don't think this should work either
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!
iSee is offline   0 Reply With Quote
Old Apr 3, 2009, 05:12 PM   #11
mdeh
macrumors 6502
 
Join Date: Jan 2009
Quote:
Originally Posted by gnasher729 View Post
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.
mdeh is offline   0 Reply With Quote
Old Apr 3, 2009, 05:21 PM   #12
autorelease
macrumors regular
 
Join Date: Oct 2008
Location: Achewood, CA
Quote:
Originally Posted by iSee View Post
I, too, don't understand what the "case 0:;" stuff is getting at.
I don't think this should work either
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)
autorelease is offline   0 Reply With Quote
Old Apr 3, 2009, 06:30 PM   #13
iSee
macrumors 68030
 
iSee's Avatar
 
Join Date: Oct 2004
Quote:
Originally Posted by autorelease View Post
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.
iSee is offline   0 Reply With Quote
Old Apr 3, 2009, 06:41 PM   #14
lazydog
macrumors 6502a
 
Join Date: Sep 2005
Location: Cramlington, UK
Send a message via MSN to lazydog
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
lazydog is offline   0 Reply With Quote
Old Apr 3, 2009, 09:37 PM   #15
autorelease
macrumors regular
 
Join Date: Oct 2008
Location: Achewood, CA
Quote:
Originally Posted by iSee View Post
(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.
autorelease is offline   0 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Similar Threads
thread Thread Starter Forum Replies Last Post
Black screen , HDMI doesn't work , VGA doesn't work Madridista Mac Basics and Help 4 Jun 23, 2014 05:45 PM
VPN by iPhone work but at MacBook doesn't work! why ? Jingol Mac Basics and Help 1 Sep 12, 2013 04:40 PM
Why doesnt the else statement work in this? bigMAC28 Mac Programming 2 Aug 4, 2013 04:44 PM
If Apple doesn't switch to OLED I am done. halo4 Wasteland 36 Jun 20, 2012 07:23 AM
Alternatives to a switch statement? GorillaPaws Mac Programming 3 Jun 14, 2012 12:18 PM

Forum Jump

All times are GMT -5. The time now is 12:19 AM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps

Mobile Version | Fixed | Fluid | Fluid HD
Copyright 2002-2013, MacRumors.com, LLC