Sử dụng tiếp tục trong câu lệnh chuyển đổi


89

Tôi muốn chuyển từ giữa một switchcâu lệnh sang câu lệnh lặp trong đoạn mã sau:

while (something = get_something())
{
    switch (something)
    {
    case A:
    case B:
        break;
    default:
        // get another something and try again
        continue;
    }
    // do something for a handled something
    do_something();
}

Đây có phải là cách hợp lệ để sử dụng continuekhông? Các continuecâu lệnh có bị bỏ qua bởi các switchcâu lệnh không? C và C ++ có khác nhau về hành vi của chúng ở đây không?


Ý tưởng của bạn là tốt nhưng vòng lặp trên sẽ không bao giờ thực thi do_something().
antik

5
Ngay cả khi quyền kiểm soát đạt đến trường hợp A hay trường hợp B?
Alexander Poluektov

18
Tôi định nói, antik đã sai về điều đó. Trong trường hợp A hoặc B thì do_something () sẽ thực thi. Với mặc định, nó sẽ được bảo lãnh.
Antony Woods

3
@acron, đó là hành vi có ý định
Matt Joiner

1
Tôi nghĩ rằng điều này trông đáng ngờ và khó hiểu hơn nhiều và do đó có hại hơn a goto.
phoeagon

Câu trả lời:


56

Không sao cả, continuecâu lệnh liên quan đến vòng lặp đi kèm và mã của bạn phải tương đương với (tránh các câu lệnh nhảy như vậy):

while (something = get_something()) {
    if (something == A || something == B)
        do_something();
}

Nhưng nếu bạn muốn breakthoát khỏi vòng lặp, như nhận xét của bạn đề xuất (nó luôn thử lại với một thứ gì đó khác, cho đến khi nó đánh giá là false), bạn sẽ cần một cấu trúc khác.

Ví dụ:

do {
    something = get_something();
} while (!(something == A || something == B));
do_something();

2
'tương đương' chỉ theo nghĩa ngữ nghĩa. mã mà trình biên dịch tạo ra rất khác nhau. với một tuyên bố chuyển đổi, trình biên dịch có thể tạo ra một bảng nhảy mà tránh nhiều sự so sánh và do đó là nhanh hơn nhiều so với so sánh với mỗi phần tử 1 bằng 1.
chacham15

@ chacham15, tại sao trình biên dịch không thể tạo cùng một mã cho cả hai?
avakar

Các câu lệnh chuyển đổi @avakar tạo ra các bảng nhảy trong khi biểu diễn khác là một chuỗi các đánh giá logic. google jump table để biết thêm thông tin.
chacham

@ chacham15, điều gì ngăn trình biên dịch tạo bảng nhảy cho hai câu lệnh if hoặc một loạt đánh giá logic cho công tắc?
avakar

1
Câu lệnh @avakar switch yêu cầu các trường hợp phải là giá trị không đổi, bởi vì đó không phải là trường hợp với câu lệnh if, nó không thể thực hiện tối ưu hóa tương tự (lưu ý: tôi đang nói trong trường hợp chung, có thể đưa ra các yêu cầu nhất định (ví dụ: chỉ giá trị const , chỉ một số toán tử logic nhất định, v.v.) để thực hiện tối ưu hóa, nhưng nó phụ thuộc nhiều vào trình biên dịch và YMMV).
chacham

20

Có, không sao - nó giống như sử dụng nó trong một ifcâu lệnh. Tất nhiên, bạn không thể sử dụng một breakđể thoát khỏi vòng lặp từ bên trong một công tắc.


Nhưng ifkhông ảnh hưởng đến hành vi của continuehoặc break. Ý bạn là nó giống nhau như thế nào?
Matt Joiner

@Matt Ý tôi là nó sẽ tiếp tục vòng lặp trong cả hai trường hợp.

1
@Neil, được rồi, tránh nhầm lẫn.
Matt Joiner

1
@ KiJéy Tôi không thể tìm thấy bất kỳ tài liệu tham khảo nào cho điều này, và trong nhiều năm lập trình C, tôi chưa bao giờ thấy bất kỳ trình biên dịch nào hỗ trợ điều này ... Bạn tìm thấy cái này ở đâu vậy?
arjunyg

2
Wow xin lỗi, tôi thấy điều này trong PHP, nghĩ rằng nó là một thực hành cũ, lần lượt ra nó chỉ là PHP ...
Ki Jey

15

Có, tiếp tục sẽ bị bỏ qua bởi câu lệnh switch và sẽ chuyển đến điều kiện của vòng lặp được kiểm tra. Tôi muốn chia sẻ phần trích xuất này từ tài liệu tham khảo Ngôn ngữ lập trình C của Ritchie:

Câu continuelệnh có liên quan đến break, nhưng ít được sử dụng hơn; nó gây ra phiên bản kế tiếp của kèm theo for, whilehoặc dovòng lặp để bắt đầu. Trong whiledo, điều này có nghĩa là phần kiểm tra được thực thi ngay lập tức; trong for, điều khiển chuyển sang bước tăng dần.

Câu lệnh continue chỉ áp dụng cho các vòng lặp, không áp dụng cho một switchcâu lệnh. Một continuebên trong một switchbên trong một vòng lặp gây ra lặp lại vòng lặp tiếp theo.

Tôi không chắc về điều đó cho C ++.


8

Nó đúng về mặt cú pháp và ổn về mặt phong cách.

Phong cách tốt yêu cầu mọi case:tuyên bố phải kết thúc bằng một trong những điều sau:

 break;
 continue;
 return (x);
 exit (x);
 throw (x);
 //fallthrough

Ngoài ra, case (x):ngay sau đó với

 case (y):
 default:

được phép - nhóm một số trường hợp có cùng tác dụng.

Bất cứ điều gì khác đang bị nghi ngờ là một sai lầm, giống như if(a=4){...} Tất nhiên bạn không cần kèm theo vòng lặp ( while, for, do...while) cho continueđến công việc. Nó sẽ không quay trở lại case()một mình. Nhưng một cấu trúc như:

while(record = getNewRecord())
{
    switch(record.type)
    {
        case RECORD_TYPE_...;
            ...
        break;
        default: //unknown type
            continue; //skip processing this record altogether.
    }
    //...more processing...
}

... ổn.


2
xin lỗi vì đã đăng tải, nhưng tôi muốn nói thêm rằng một cuộc gọi đến exitcũng thường là một điều tốt để kết thúc trường hợp chuyển đổi.
Vality

1
Vâng, tôi sẽ nhận được tất cả các bác sĩ Frankenstein ở đây và cũng chỉ ra rằng default:không nhất thiết phải là đáy mục cuối cùng / - như này điểm câu hỏi ra ...
SlySven

1
@SlySven: Nói một cách cụ thể thì không, nhưng nếu bạn không có lý do chính đáng để không kéo dài nó, hãy làm cho nó tồn tại. Nó thường gây nhầm lẫn nếu được sử dụng ở những nơi khác.
SF.

1
@SF. tốt, tôi có thể dễ dàng hình dung các trường hợp khi đặt default:trường hợp đầu tiên thay vì trường hợp cuối cùng sẽ có ý nghĩa hơn . Giống như "làm điều này, trừ khi bạn nhận được các giá trị bất thường sau đây, giá trị này sẽ được xử lý như sau".
Ruslan

5

Mặc dù hợp lệ về mặt kỹ thuật, tất cả các bước nhảy này đều che khuất luồng điều khiển - đặc biệt là continuecâu lệnh.

Tôi sẽ sử dụng một thủ thuật như vậy như một phương sách cuối cùng, không phải phương án đầu tiên.

Làm thế nào về

while (something = get_something())
{
    switch (something)
    {
    case A:
    case B:
        do_something();
    }        
}

Nó ngắn hơn và trình diễn nội dung của nó một cách rõ ràng hơn.


1
xin lỗi vì sự nhầm lẫn này Alexander, mã chỉ dùng để trình diễn, tôi có lý do chính đáng (tôi tin) cho cấu trúc thực tế trong mã của mình.
Matt Joiner

2
@Matt: Điều đó có thể có nghĩa là một cấu trúc thậm chí còn khó hiểu hơn ... :)
khách truy cập

-2

Đây có thể là một megabit đến muộn nhưng bạn có thể sử dụng continue 2.

Một số bản dựng / cấu hình php sẽ xuất ra cảnh báo này:

Cảnh báo PHP: Chuyển đổi nhắm mục tiêu "tiếp tục" tương đương với "ngắt". Ý của bạn là sử dụng "tiếp tục 2"?

Ví dụ:

$i = 1;

while ($i <= 10) {
    $mod = $i % 4;
    echo "\r\n out $i";
    $i++;
    switch($mod)
    {
        case 0:
            break;
        case 2:
            continue;
            break;
        default:
            continue 2;
            break;
    }
    echo " is even";
}

Điều này sẽ xuất ra:

out 1
out 2 is even
out 3
out 4 is even
out 5
out 6 is even
out 7
out 8 is even
out 9
out 10 is even

Đã thử nghiệm với PHP 5.5 trở lên.


3
Đây KHÔNG phải là một câu hỏi PHP.
Geoffrey

-4

Switch không được coi là vòng lặp nên bạn không thể sử dụng Tiếp tục bên trong một câu lệnh trường hợp trong switch ...


3
Câu switchlệnh nằm trong một whilevòng lặp, vì vậy continuehoàn toàn hợp lệ.
Rick,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.