2015-07-22 18 views
23

Tôi đã chơi với một số cú pháp và tìm thấy một số quy tắc biên dịch lạ, đã tự hỏi những gì các lập luận là choC vs C++ định nghĩa biến câu lệnh switch vs khai

C này sẽ không biên dịch này nhưng C++ sẽ:

switch (argc) { 
case 0: 
    int foo; 
    break; 
default: 
    break; 
} 

Cả C và C++ sẽ biên dịch này:

switch (argc) { 
case 0: 
    ; int foo; 
    break; 
default: 
    break; 
} 

C sẽ biên dịch này nhưng không phải C++:

switch (argc) { 
case 0: 
    ; int foo = 0; 
    break; 
default: 
    break; 
} 

gcc -vgcc version 4.9.3 (MacPorts gcc49 4.9.3_0) nếu vấn đề. Tôi nhận ra giải pháp là để bọc các nội dung của case 0: với dấu ngoặc nhọn, nhưng tôi quan tâm nhiều hơn trong lập luận cho lỗi biên dịch

+5

[Câu trả lời này] (http://stackoverflow.com/a/92730/962089) có phần liên quan. – chris

+2

Dường như trường hợp thứ hai vẫn hoạt động với C++ nếu bạn đặt 'foo' trong câu lệnh bổ sung. gcc chỉ phàn nàn về biến không sử dụng trong [ví dụ này] (http://coliru.stacked-crooked.com/a/ba80bc1da97d8212), và clang là tốt với nó. – jaggedSpire

+1

@chris, Cảm ơn, trường hợp thứ ba có ý nghĩa bây giờ (không thể nhảy qua khởi tạo trong C++) – asimes

Trả lời

23
case 0: 
    int foo; 

Trong cả hai C và C++ một tuyên bố nhãn là một nhãn theo sau là một tuyên bố. Tuy nhiên trong C++ định nghĩa của một câu lệnh bao gồm "khai báo khối" (đó là khai báo và định nghĩa có thể xuất hiện trong một khối) trong khi trong C nó không (trong khối C là chuỗi "block items". các khai báo hoặc các câu lệnh - trong C++ nó là một chuỗi các câu lệnh, bao gồm các khai báo khối).

case 0: 
    ; int foo; 

này hoạt động vì ; là một (n trống) tuyên bố trong cả C và C++, vì vậy ở đây chúng tôi thực sự có một nhãn hiệu theo sau là một tuyên bố.

case 0: 
    ; int foo = 0; 

Như đã được giải thích trong các nhận xét, điều này không hoạt động trong C++ vì C++ làm cho nó bất hợp pháp để nhảy qua khởi tạo.

+0

Đây là một câu trả lời hay nhưng trường hợp thứ ba vẫn là câu lệnh gây nhầm lẫn cho tôi nhiều nhất. Làm thế nào nó nhảy qua một khởi tạo? Tại sao việc đặt định nghĩa bên trong dấu ngoặc nhọn tránh nhảy qua khởi tạo? – asimes

+1

@ lần, khi bạn đặt niềng răng, '{; int foo = 0;} 'là câu lệnh cho câu lệnh * có nhãn *. Khi bạn không, 'int foo = 0;' là một phần của chuyển đổi chứ không phải là một câu lệnh cho một trường hợp, vì vậy nó nằm trong phạm vi ngoài nhãn kế tiếp, nhưng khởi tạo của nó bị bỏ qua. – chris

+0

@asimes Nó có khả năng nhảy qua khởi tạo vì nó có thể chuyển đến trường hợp mặc định, trong đó 'foo' sẽ nằm trong phạm vi, nhưng không được khởi tạo. Nếu bạn thêm dấu ngoặc ôm, 'foo' không còn nằm trong phạm vi trong khối mặc định nữa.Về cơ bản, các quy tắc "nhảy qua khởi tạo" cấm bạn nhảy "ở giữa" của phạm vi của một biến có bộ khởi tạo. Tức là, bạn được phép nhảy tới khởi tạo hoặc sau khi biến đã biến mất khỏi phạm vi, nhưng không được phép ở bất kỳ đâu giữa các điểm đó. – sepp2k