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
,语句是statement
。 statement
意味着多种事物,其中之一被称为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
定义中,从而允许下一个“语句”成为statement
或declaration
。
我还没有调查过这是否是对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?