Obj中奇怪的开关错误

我的代码中有这个switch语句:

switch(buttonIndex){
      case 0:
         [actionSheet dismissWithClickedButtonIndex:buttonIndex animated:YES];
         break;
    case 1:
        UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
        imagePicker.delegate = self;
        imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
        [self presentModalViewController:[imagePicker autorelease] animated:YES];
        break;
    default:
        [self openEmailViewInViewController:self];
}

在案例1的UIImagePickerController实例中,我收到一个错误:

error:expected expression before 'UIImagePickerController'

我不知道我做错了什么。 思考?

哦,并且buttonIndex是一个NSInteger


您不能在案例标签之后立即声明变量。


我遇到了这个问题,有一天我决定深入研究它。

简短但不实际的解决方案:

解决这个“问题”的方法是使用一个分号, ; ,在case ...:的冒号之后case ...:声明。 例如,使用您提供的示例,它可以是“固定的”,因此它的编译和行为与您直观地期望的一样:

    case 1:; // <- Note semi-colon.
            UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
            imagePicker.delegate = self;

长答案:

一些历史:以前,C只允许你在块的开始声明“块本地”变量,然后是各种语句。 C99改变了事情,所以你可以自由混合变量声明和语句。

在C99 BNF语法的上下文中,变量声明是declaration ,语句是statementstatement意味着多种事物,其中之一被称为compound-statement ,这是熟悉的{ ... }块。 该...部分宽松地定义为zero or more block-items ,有block-item被宽泛地定义为either a declaration or a statement

问题在于定义了labeled-statement (goto标签,case标签或default:本质上是...:语句)的方式,它被松散地定义为...: zero or more statements 。 正如人们可以直观地预料的那样,它不是, zero or more statements or declarations 。 使用a ; 在之后labeled-statement小号:基本终止zero or more statements一个的一部分labeled-statement 。 这会导致语法回到compound-statement定义中,从而允许下一个“语句”成为statementdeclaration

我还没有调查过这是否是对C99语言规范的无意忽视(实际上,这是C99标准中的一个错误),或者这是对编写语言语法的复杂性的实际让步。 如果你对编写语法不熟悉,你会注意到上面的解释允许递归: labeled-statement可以匹配case 1: case 2: case 3: 在过于简单的术语(1) ,某些类型的语法递归很简单且“明确”,而另一些类型是复杂且“模糊”的。 为了简单起见,大多数语言工具只会处理必须通过查看“下一个标记”来确定解决任何歧义的情况。 我只提到这一点,因为虽然这可能在直觉上看起来像C99规范中的一个缺陷,但可能存在令人信服的非显而易见的原因,这是为什么存在的......我并没有打算对此主题进行任何进一步的研究以找出无论哪种方式。

(1)这不意味着是一个技术上准确的描述,而是对不熟悉涉及问题的人的合理近似。

编辑:

我给出的解决方案在“大多数”情况下工作(情况是“用法”,而不是switch case ),但在一种情况下失败:当声明声明C99 variable length array ,这将不起作用,例如case 1:; void *ptrs[count]; case 1:; void *ptrs[count]; 这是因为在C99中,“跳过”C99 VLA的声明是错误的,该声明位于发生跳转的相同词法范围内。 在这些情况下,您需要使用case 1: { void *ptrs[count]; } case 1: { void *ptrs[count]; } 。 在这种情况下, ptrs VLA的范围在结束时结束} 。 这比第一次出现更复杂,因为以下是完全合法的C代码,但乍一看,人们会直觉地认为它不是:

switch(3){
  case 0:
    printf("case 0n");
    break;
  case 1:;
    int *ip = NULL;
    printf("case 1n");
    break;
  case 2:
    {
      int ia[6];
      printf("case 2n");
      break;
      case 3:
        printf("case 3n");
        break;
      default:
        printf("defaultn");
    }
}

这编译,并在运行时,打印case 3

另见:维基百科:达夫设备


我喜欢在这种情况下做的一件事是把每个case的内容放在大括号内。 这是编译器允许的:

switch (buttonIndex)
{
    case 0:
    {
        [actionSheet dismissWithClickedButtonIndex:buttonIndex animated:YES];
        break;
    }
    case 1:
    {
        UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
        imagePicker.delegate = self;
        imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
        [self presentModalViewController:[imagePicker autorelease] animated:YES];
        break;
    }
    default:
    {
        [self openEmailViewInViewController:self];
    }
}
链接地址: http://www.djcxy.com/p/2415.html

上一篇: Weird Switch error in Obj

下一篇: What is the best way to detect a mobile device in jQuery?