views:

3128

answers:

4

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?

+1  A: 

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

Novelocrat
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
+10  A: 

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
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
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
+5  A: 

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
False. `switch (0) { int i; }` compiles perfectly fine even back in C89.
ephemient
Not false. I just ran your example from Aragorn's post through GCC and got the same error.
Chuck
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
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
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
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
@Dan: GCC does not warn about this. I tested it.
Chuck
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
+2  A: 

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
`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
with visual studio 2008 compiling a c file. is -> error C2143: syntax error : missing ';' before 'type'=)
Aragorn
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
In C mode (/TC) it gives the error and in C++ mode (/TP) it compile without error. =)
Aragorn