57

I think I'm going blind, because I can't figure out where the syntax error is in this code:

if( cell == nil ) {
    titledCell = [ [ [ TitledCell alloc ] initWithFrame:CGRectZero
        reuseIdentifier:CellIdentifier ] autorelease
    ];

    switch( cellNumber ) {
        case 1:
            NSString *viewDataKey = @"Name";
etc...

When I try to compile it, I'm getting an Error: syntax error before '*' token on the last line.

Sorry for such a basic question, but what am I missing?

Jim Puls
  • 79,175
  • 10
  • 73
  • 78
JoBu1324
  • 7,751
  • 6
  • 44
  • 61
  • 1
    What kind of variable is cellNumber? The switch statement is from C, so using Objective-C types can trip it up. – Jeff Kelley Jul 12 '09 at 04:29
  • 1
    C only supports integral-like objects for `switch/case`, and I'd expect a different error message if that were the problem here. – ephemient Jul 12 '09 at 04:32
  • Does Objective-C follow C99 (and C++) and allow you to declare variables anywhere, or can you only do so at the start of a block? If you are constrained to declare them at the start of a block, then you could fix your syntax error by putting a '`{`' after the '`:`' of '`case 1:`' and a matching '`}`' before the end of the case. – Jonathan Leffler Jul 12 '09 at 04:35
  • I don't know if Objective-C is forked off of C89 or if it borrows C99/C++ constructs too. Either way, jumping *over* declarations is really scary... – ephemient Jul 12 '09 at 04:37
  • You can set C89 or C99 (or GNU99) as a build property in Xcode; Objective-C lays on top of your choice of C standards. – Jim Puls Jul 12 '09 at 05:12
  • I believe C99 is the default (declaring an incrementor inside a for loop works: for (int i =0;...), and I believe that's C99). – jbrennan Jul 24 '09 at 23:03
  • Related, valuable question and answer, focusing in C only: http://stackoverflow.com/questions/92396/why-cant-variables-be-declared-in-a-switch-statement – brandizzi Jan 28 '14 at 15:24

6 Answers6

74

I don't have a suitable Objective-C compiler on hand, but as long as the C constructs are identical:

switch { … } gives you one block-level scope, not one for each case. Declaring a variable anywhere other than the beginning of the scope is illegal, and inside a switch is especially dangerous because its initialization may be jumped over.

Do either of the following resolve the issue?

NSString *viewDataKey;
switch (cellNumber) {
    case 1:
        viewDataKey = @"Name";
    …
}

switch (cellNumber) {
    case 1: {
        NSString *viewDataKey = @"Name";
        …
    }
    …
}
ephemient
  • 198,619
  • 38
  • 280
  • 391
  • 2
    wrt/ `Declaring a variable anywhere other than the beginning of the scope is illegal`. This is not true in C99. C99 both allows for this and defines the semantics of what happens when "control jumps past a declaration" and the value of that declaration in such cases. – johne Jul 25 '09 at 03:46
  • I forgot to indicate which option solved the problem, oops. I used the top one to solve the problem - I don't think I tested the second suggestion, which is too bad, because you guys look like you were having a great discussion! – JoBu1324 Sep 03 '09 at 08:35
20

You can't declare a variable at the beginning of a case statement. Make a test case that just consists of that and you'll get the same error.

It doesn't have to do with variables being declared in the middle of a block — even adopting a standard that allows that won't make GCC accept a declaration at the beginning of a case statement. It appears that GCC views the case label as part of the line and thus won't allow a declaration there.

A simple workaround is just to put a semicolon at the beginning of the case so the declaration is not at the start.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • 1
    False. `switch (0) { int i; }` compiles perfectly fine even back in C89. – ephemient Jul 12 '09 at 04:39
  • Not false. I just ran your example from Aragorn's post through GCC and got the same error. – Chuck Jul 12 '09 at 04:59
  • I'm claiming that "can't declare a variable in a case statement" is false. Try giving GCC the tiny example in my previous comment. – ephemient Jul 12 '09 at 05:05
  • There is no case statement in your comment, so it's irrelevant to the content of my post. Also, I have clarified my answer slightly. – Chuck Jul 12 '09 at 05:10
  • 1
    Oh, I see, you were talking about the `case` label specifically and not the `switch`. Confusing to talk about the "beginning" of it -- `case` is just a *label*, and as such can only label statements. That is a valid point. – ephemient Jul 12 '09 at 05:24
  • Semicolon at the beginning of the case statement doesn't solve the problem, which is that a jump across the initialization of a variable is happening. Every good compiler will warn about this. The correct fix is to enclose the case statement in brackets, giving the variable a well-defined scope. – Dan Olson Jul 24 '09 at 23:10
  • @Dan: GCC does not warn about this. I tested it. – Chuck Jul 25 '09 at 01:01
  • 6
    The poster of this answer is correct. The root of the problem lies in the C99 BNF grammar, which (loosely) defines a labeled statement as: `...: statement`. In short, there is no way to get from `statement` to `declaration`. A `compound-statement` (ie, `{ ... }`) (loosely) defines the `...` part as `zero or more block-items`, with block-item (loosely) defined as a `statement or declaration`. Also, the comment by @Dan Olson is both wrong and does not apply to C99, which very clearly defines the semantics of inter-mixed declarations and statements wrt/ initialization (C99 6.8.6.1, etc). – johne Jul 25 '09 at 03:41
4

In C you only can declare variables at the begining of a block before any non-declare statements.

{
   /* you can declare variables here */

   /* block statements */

   /* You can't declare variables here */
}

In C++ you can declare variables any where you need them.

Aragorn
  • 843
  • 12
  • 25
  • `switch (1) { case 0: int i = 1; break; default: /* wtf is i? */; }` Even if you can declare variables everywhere, inside a `switch` is *dangerous*. – ephemient Jul 12 '09 at 04:46
  • with visual studio 2008 compiling a c file. is -> error C2143: syntax error : missing ';' before 'type' =) – Aragorn Jul 12 '09 at 05:00
  • Skipping over initializers in C++ is even more dangerous than in C, and MSVC is more of a C++ compiler than a C compiler. I'm not surprised that it doesn't like this junk. – ephemient Jul 12 '09 at 05:07
  • In C mode (/TC) it gives the error and in C++ mode (/TP) it compile without error. =) – Aragorn Jul 12 '09 at 05:16
2

You can create a variable within a switch statement but you will have to create it within a block so that the scope of that variable is defined.

Example:

switch(number){

    case 1:
        {
            // Create object here
            // object is defined only for the scope of this block
        }
        break;
    case 2:
        {
            // etc.
        }
        break;
    default:
        break;

}
egarlock
  • 559
  • 3
  • 11
  • This is a new answer to a very old question with an accepted answer. What does your answer provide that the others do not? – JAL Dec 22 '16 at 20:41
  • This was meant to be an alternative to the 1st switch statement presented in the accepted answer. At the time of posting I had not noticed the bracket inline with the case statement in the 2nd switch statement provided. – egarlock Dec 22 '16 at 20:53
1

Might it not be valid to declare a variable within a switch block?

Phil Miller
  • 36,389
  • 13
  • 67
  • 90
  • As I remarked on Chuck's answer: `switch (0) { int i; }` is valid C89, and Objective-C is a true superset of C (unlike C++), so everything legal in C (modulo stolen identifiers) is legal in Objective-C. – ephemient Jul 12 '09 at 04:41
0

How to solve the warning:

1.Insert one ; in the first line of your case block

2.Put codes inside braces

Jianxin Gao
  • 2,717
  • 2
  • 19
  • 32
lin zheng
  • 40
  • 3