为什么我们不能在不使用花括号的情况下在switch case冒号之后声明变量?

时间:2017-12-25 17:44:23

标签: c

case 1:
            { //question is about this curly brace
                int val;
                scanf("%d", &val);
                if(top1 == NULL){
                    enqueue(top1, val, bottom1);
                }
                else{
                    enqueue(top1, val);
                }
                break;
            }

在案例1之后没有大括号:它给出了一个错误:*

  

标签只能是声明的一部分而声明不是a   声明:int val;

*

3 个答案:

答案 0 :(得分:2)

这就是C语法的定义方式。变量声明不被视为语句:

int x; //a declaration
int y = 3; //another declaration
x = y + 1; //a statement

标签必须后跟声明。不允许使用标签和声明。

foo: int x; //error
bar: x = y +1; //ok

即IMO,不方便:

while (...)
{
    //...
    goto end;
    end:   //error, no statement   
}

请记住,case只是一种特殊的标签,所以:

case 1: int x; //error
case 2: x = y +1; //ok

大括号的问题在于,它们用于构建复合语句,这当然是一种语句。复合语句中的行可以是声明和语句,都是混合的(旧的C版本只允许在开头声明,而不是在中间)。所以:

case 1: int x; //error: label plus declaration
case 2: { int x; } //ok: label plus compound statement

作为脚注,由于现代C允许混合声明和语句,您还可以写:

case 1:; int x; //ok: label plus empty statement.

因为隔离的;是一个空语句,所以只要需要一个无操作语句,它就可以用来满足语法。

是否使用;{ ... }是可读性的问题。在end:示例中,我使用;,但在case:我更喜欢{...}

while (...)
{
    //...
    goto end;
    end:;   //ok, empty statement   
}

switch (...)
{
    case 1: //ok, compound statement
    {
        int x;
    }
}

当然可以编写更具创造性的解决方案,例如:

case 1: {} int x; //ok, label plus empty compound statement

答案 1 :(得分:2)

关于案例标签的C规则

阻止声明遵循案例标签的C标准规则如下:

  • 案例标签后面必须跟陈述(C 2011 [N1570] 6.8.1)。

  • C标准将语句定义为标记语句复合语句表达式语句之一 selection-statement iteration-statement jump-statement (6.8)。这些都不是声明

C标准分别处理声明和声明。允许声明与语句混合的规则是 compound-statement 是大括号中 block-item 的列表(即 {< / strong> block-item-list opt } )(6.8.2)和块项目被定义为声明声明。因此,在大括号内,您可以混合声明和语句。但案件标签必须是声明的一部分;它不是一个单独的东西,你可以插入任何地方。

声明可以使用两个备选方案包含在交换机内。一种是在案例标签后使用空语句,如:

case 123:
    ;
    int foo;
    …

另一种方法是在案例标签之后使用复合语句,如:

case 123:
{
    int foo;
    …
}

通常,后者是优选的,因为foo的范围仅限于复合语句,因此不能在switch语句的另一部分中意外使用。

规则的原因

除了历史,我没有看到这个原因。最初,声明比现在更加严格。在函数内部,声明必须是大括号内的第一个语句。在任何声明之后你都不能发表声明。在现代C中已经放松了,但为什么对案例标签后面的内容仍有限制?

声明不能遵循现代C中的case标签,因为上面的空语句示例与语句具有相同的语义:

case 123:
    int foo;

也就是说,编译器必须准备好在执行的同一点创建和初始化一个新对象。由于它必须为合法的示例代码执行此操作,因此它也可以为此版本执行此操作。

我也没有看到句法或语法障碍。在案例标签的不断表达之后的冒号是非常明显的。 (常量表达式可以在? :运算符中包含冒号,但与:无关的第一个?将是案例标签的结尾。)一旦解析到达该冒号,当前的解析状态似乎很干净。我不明白为什么它不能在那里承认声明或声明,正如它准备在case之前做的那样。

(如果某人可以在语法中发现一个问题,那就是允许一个案例标签后面跟一个声明,这会很有趣。)

答案 2 :(得分:0)

首先要说的是,您发布的错误是与import UIKit import GooglePlacePicker class ViewController: UIViewController { // Add a pair of UILabels in Interface Builder, and connect the outlets to these variables. @IBOutlet var nameLabel: UILabel! @IBOutlet var addressLabel: UILabel! // The code snippet below shows how to create and display a GMSPlacePickerViewController. @IBAction func pickPlace(_ sender: UIButton) { let config = GMSPlacePickerConfig(viewport: nil) let placePicker = GMSPlacePickerViewController(config: config) present(placePicker, animated: true, completion: nil) } // To receive the results from the place picker 'self' will need to conform to // GMSPlacePickerViewControllerDelegate and implement this code. func placePicker(_ viewController: GMSPlacePickerViewController, didPick place: GMSPlace) { // Dismiss the place picker, as it cannot dismiss itself. viewController.dismiss(animated: true, completion: nil) print("Place name \(place.name)") print("Place address \(place.formattedAddress)") print("Place attributions \(place.attributions)") } func placePickerDidCancel(_ viewController: GMSPlacePickerViewController) { // Dismiss the place picker, as it cannot dismiss itself. viewController.dismiss(animated: true, completion: nil) print("No place selected") } } 标签语句格式相关的语法错误。它允许您只使用可执行语句,而不是声明。在声明之前放一个空的陈述,你就可以了。请尝试以下方法:

case

第一个变量#include <stdio.h> int main() { switch(3) { int x = 3; /* the initializer is ignored by the compiler * you can include declarations here, but as * this code is never executed, the initializer * never takes place. */ case 3:; /* <=== look this semicolon to allow the next declaration */ int y = 5; printf("x = %d, y = %d\n", x, y); break; } } 将被正确声明,但初始化程序将不会被执行,因为所选的case语句是与case标签x对应的case语句。 3将打印

printf

(注意:这发生在我的机器上,因为变量x = 0, y = 5 未初始化,未定义行为 预期)

在C中,多年来已经实现了一些关于在块中使用声明的演变。

在古代C中,变量只能在块的开头(x{之间的代码片段声明,但是这种方法已被抛出,因为新的可能性是声明变量无论何时需要它(即使在块开始后的一些可执行句子之后)但是}语句只允许放置可执行语句,而不是声明,这就是编译器错误的原因。 / p>

如果你遵循古老的C方式,你只能在切换后打开case大括号之后声明新的局部变量,如:

{

虽然违反直觉,但自旧的K&amp; R代码起有效。这种方法的问题在于变量从定义点到switch语句结束都是有效的,因此,它对所有案例部分都是全局的。

另一种方式,是你建议的形式,你通过打开花括号来声明一个新的块。这也适用于旧的K&amp; R代码,并且更容易控制定义的变量的范围。就个人而言,我更喜欢第二种方法。块是一个可执行语句,因此使用它作为交换机的带标签的case语句没有问题(声明发生在它内部)。

案例标签不分隔代码块,它们标记可执行语句,因此它们的语法特定于switch(something) { int var1; case BLA_BLA: /* use var1 here */ 语句语法(在附加到语句的分号后完成,或者关闭卷曲br)