'<' so với '! =' là điều kiện trong vòng lặp 'cho'?


31

Giả sử bạn có forvòng lặp sau *:

for (int i = 0; i < 10; ++i) {
    // ...
}

mà nó thường có thể được viết là:

for (int i = 0; i != 10; ++i) {
    // ...
}

Kết quả cuối cùng là như nhau, vậy có bất kỳ đối số thực tế nào cho việc sử dụng cái này hơn cái kia không? Cá nhân tôi sử dụng trước đây trong imột số trường hợp vì lý do đi haywire và bỏ qua giá trị 10.

* Xin lỗi vì sử dụng số ma thuật, nhưng đó chỉ là một ví dụ.


18
Giải pháp ưu việt cho một trong hai là sử dụng toán tử mũi tên:int i = 10; while(i --> 0) { /* stuff */ }
corsiKa

@glowcoder toán tử mũi tên là sở thích của tôi
Carson Myers

3
@glowcoder, đẹp nhưng nó di chuyển từ phía sau. Bạn có thể không luôn luôn muốn điều đó.

2
@SuperElectric, nó phân tích cú pháp nhưwhile ((i--) > 0)
Kristopher Johnson

17
Có một câu chuyện (có lẽ là tận thế) về một tai nạn công nghiệp gây ra bởi một thử nghiệm vòng lặp while cho đầu vào cảm biến! = MAX_TEMP. Thật không may, một ngày, đầu vào cảm biến chuyển từ nhỏ hơn MAX_TEMP sang lớn hơn MAX_TEMP mà không qua MAX_TEMP. Quá trình quá nóng mà không được phát hiện, và một đám cháy xảy ra. Đôi khi có sự khác biệt giữa! = Và <.
Charles E. Grant

Câu trả lời:


59

Lý do để chọn cái này hay cái kia là vì ý định và kết quả của việc này, nó làm tăng khả năng đọc .

Ý định: vòng lặp sẽ chạy trong khoảng thời gian inhỏ hơn 10, không phải ilà không bằng 10. Mặc dù cái sau có thể giống nhau trong trường hợp cụ thể này, nhưng đó không phải là ý bạn, vì vậy nó không nên được viết như thế.

Khả năng đọc: kết quả của việc viết ra những gì bạn muốn nói là nó cũng dễ hiểu hơn. Ví dụ: nếu bạn sử dụng i != 10, ai đó đang đọc mã có thể tự hỏi liệu bên trong vòng lặp có cách nào đó icó thể trở nên lớn hơn 10 hay không và vòng lặp đó có tiếp tục không (btw: đó là phong cách xấu để gây rối với trình vòng lặp ở đâu đó ngoài đầu sự thay đổi for, nhưng điều đó không có nghĩa là mọi người không làm điều đó và kết quả là những người duy trì mong đợi nó).


3
Không, vòng lặp không nên chạy miễn ilà nhỏ hơn 10v, nó sẽ chạy miễn là không đạt được giới hạn trên (trong trường hợp này). Khi sử dụng cơ sở phạm vi khoảng thời gian / vòng lặp C ++, việc thể hiện điều này thông qua logic !=hơn nhiều <.
Konrad Rudolph

14
@Konrad Tôi không đồng ý với điều đó. Điểm chính không phải là giáo điều, mà là chọn cấu trúc thể hiện rõ nhất ý định của điều kiện. Và vì vậy, nếu bạn chọn lặp qua một cái gì đó bắt đầu từ 0 và di chuyển lên, thì <thực sự thể hiện chính xác điều đó.
Deckard

6
@Konrad, bạn đang thiếu điểm. Toán tử gia tăng trong vòng lặp này cho thấy rõ rằng điều kiện vòng lặp là giới hạn trên, không phải là so sánh danh tính. Nếu bạn đang giảm, nó sẽ là một giới hạn thấp hơn. Nếu bạn đang lặp lại một bộ sưu tập không theo thứ tự, thì danh tính có thể là điều kiện phù hợp.
Alex Feinman

3
@Alex sự gia tăng không phải là quan điểm của tôi. Một khoảng thậm chí không nhất thiết phải có một đơn đặt hàng. Nó chỉ lặp đi lặp lại trên rất tốt, một cái gì đó cho đến khi nó kết thúc. Ví dụ, các phần tử trong một bộ băm. Trong C ++, điều này được thực hiện bằng cách sử dụng các vòng lặp và một forvòng lặp. Sử dụng <ở đây sẽ là ngớ ngẩn. Ngoài ra, Deckard dường như thừa nhận điều đó. Tôi rất đồng ý với nhận xét của anh ấy để đáp lại tôi.
Konrad Rudolph

1
Lưu ý, nếu bạn sử dụng bộ đệm quay với con trỏ đuổi, bạn PHẢI sử dụng!=
SF.

48

Các < mô hình nói chung là có thể sử dụng ngay cả khi tăng xảy ra không phải là 1 cách chính xác.

Điều này cho phép một cách phổ biến duy nhất để thực hiện các vòng lặp bất kể nó được thực hiện như thế nào.


6
Nó cũng cho phép isửa đổi bên trong vòng lặp hoàn toàn an toàn nếu cần.
Matthew Scharley

1
hoặc nếu 'i' bị sửa đổi hoàn toàn không an toàn ... Một nhóm khác gặp sự cố máy chủ kỳ lạ. Nó liên tục báo cáo việc sử dụng CPU 100% và nó phải là một vấn đề với máy chủ hoặc hệ thống giám sát, phải không? Không, tôi đã tìm thấy một điều kiện vòng lặp được viết bởi một 'lập trình viên cao cấp chuyên gia' với cùng một vấn đề mà chúng ta đang nói đến.
jqa

12
Ngoại trừ việc không phải tất cả C ++ cho các vòng lặp đều có thể sử dụng <, chẳng hạn như các vòng lặp trong một chuỗi, và do đó !=sẽ là một cách phổ biến duy nhất để thực hiện các vòng lặp trong C ++.
David Thornley

@SnOrfus: Tôi không hoàn toàn phân tích nhận xét đó. Nói chung, bạn sẽ không nhận được các ngoại lệ đáng tin cậy khi tăng một trình vòng lặp quá nhiều (mặc dù có nhiều tình huống cụ thể hơn mà bạn sẽ làm).
David Thornley

Vâng, tôi theo <mô hình bởi vì nó yêu cầu một tổ hợp phím thay vì hai với >mô hình và bốn với !=. Đó thực sự là một vấn đề về hiệu quả giống như OCD.
Spoike

21

Trong C ++, khuyến nghị của Scott Myers trong C ++ hiệu quả hơn (mục 6) là luôn sử dụng lần thứ hai trừ khi bạn có lý do không phải vì điều đó có nghĩa là bạn có cùng cú pháp cho các chỉ số lặp và số nguyên để bạn có thể trao đổi liên tục giữa int và iterator không có bất kỳ thay đổi trong cú pháp.

Trong các ngôn ngữ khác, điều này không áp dụng nên tôi đoán < có lẽ thích hợp hơn vì quan điểm của Thorbjørn Ravn Andersen.

Nhân tiện, hôm nọ tôi đang thảo luận điều này với một nhà phát triển khác và anh ta nói lý do thích <hơn !=là vì icó thể vô tình tăng nhiều hơn một, và điều đó có thể khiến điều kiện phá vỡ không được đáp ứng; đó là IMO một tải vô nghĩa.


17
"Tải vô nghĩa" ... cho đến ngày bạn vô tình có thêm i ++ trong phần thân của vòng lặp.

2
+1, đặc biệt đối với tải trọng của vô nghĩa, vì nó là. Nếu thân vòng lặp vô tình làm tăng bộ đếm, bạn có vấn đề lớn hơn nhiều.
Konrad Rudolph

12
@B Tyler, chúng tôi chỉ là con người, và những sai lầm lớn hơn đã xảy ra trước đây. Xem xét <để lập trình phòng thủ nhiều hơn !=sau đó ...

2
@ Thorbjørn Ravn Andersen - Tôi không nói rằng tôi không đồng ý với bạn, tôi làm vậy; <phòng thủ hơn và các đồng nghiệp của tôi ghét nó nếu tôi viết !=vì vậy tôi không. Tuy nhiên, có một trường hợp cho !=C ++ và đó là những gì tôi đã trình bày.

9
Một kịch bản trong đó người ta có thể kết thúc bằng một phụ vô tình i++là khi thay đổi một vòng lặp while thành một vòng lặp for. Không chắc chắn rằng có một nửa số lần lặp là tốt hơn so với vòng lặp vô hạn (gần-); cái sau có lẽ sẽ làm cho lỗi rõ ràng hơn.
ak2

12

Sử dụng (i <10) theo ý kiến ​​của tôi là một thực hành an toàn hơn. Nó nắm bắt số lượng tối đa các trường hợp bỏ thuốc tiềm năng - mọi thứ lớn hơn hoặc bằng 10. Tương phản điều này với trường hợp khác (i! = 10); nó chỉ bắt được một trường hợp bỏ có thể - khi tôi chính xác là 10.

Một sản phẩm phụ của điều này là nó cải thiện khả năng đọc. Ngoài ra, nếu số gia tăng là bất cứ thứ gì khác, nó có thể giúp giảm thiểu khả năng xảy ra sự cố nếu chúng ta viết sai khi viết trường hợp bỏ thuốc.

Xem xét:

1) for (i = 1; i < 14; i+=2)

2) for (i = 1; i != 14; i+=2)

Mặc dù cả hai trường hợp đều có khả năng sai sót / sai, nhưng trường hợp thứ hai có thể sai nhiều hơn vì nó sẽ không thoát. Trường hợp đầu tiên sẽ thoát ra, và có nhiều khả năng nó sẽ thoát ra đúng chỗ, mặc dù 14 có lẽ là con số sai (15 có lẽ sẽ tốt hơn).


Trường hợp đầu tiên có thể đúng! Nếu bạn muốn lặp lại tất cả các số tự nhiên nhỏ hơn 14, thì không có cách nào tốt hơn để diễn đạt nó - tính toán giới hạn trên "đúng" (13) sẽ là ngu ngốc.
maaartinus

9

Đây là một câu trả lời khác mà dường như không ai nghĩ ra. forcác vòng lặp nên được sử dụng khi bạn cần lặp lại qua một chuỗi . Sử dụng !=là phương pháp ngắn gọn nhất để nêu điều kiện kết thúc cho vòng lặp. Tuy nhiên, sử dụng một toán tử ít hạn chế hơn là một thành ngữ lập trình phòng thủ rất phổ biến. Đối với số nguyên, điều đó không thành vấn đề - đó chỉ là một lựa chọn cá nhân mà không có ví dụ cụ thể hơn. Vòng qua các bộ sưu tập với các trình vòng lặp mà bạn muốn sử dụng !=vì những lý do mà những người khác đã nêu. Nếu bạn xem xét các chuỗi của floathoặc double, thì bạn muốn tránh!= bằng mọi giá.

Những gì tôi muốn chỉ ra là nó forđược sử dụng khi bạn cần lặp lại qua một chuỗi. Trình tự được tạo có điểm bắt đầu, khoảng thời gian và điều kiện kết thúc. Đây là những quy định chính xác trong fortuyên bố. Nếu bạn thấy mình (1) không bao gồm phần bước của forhoặc (2) chỉ định một cái gì đó như trueđiều kiện bảo vệ, thì bạn không nên sử dụngfor vòng lặp!

Các whilevòng lặp được sử dụng để tiếp tục xử lý trong khi một điều kiện cụ thể được đáp ứng. Nếu bạn không xử lý một chuỗi, thì có lẽ bạn muốn một whilevòng lặp thay thế. Các đối số điều kiện bảo vệ là tương tự ở đây, nhưng quyết định giữa a whileforvòng lặp phải là một ý thức rất có ý thức. Cácwhile vòng lặp là được đánh giá đúng trong vòng tròn C ++ IMO.

Nếu bạn đang xử lý một bộ sưu tập các mục (một forcách sử dụng -loop rất phổ biến ), thì bạn thực sự nên sử dụng một phương pháp chuyên biệt hơn. Thật không may, std::for_eachlà khá đau đớn trong C ++ vì một số lý do. Trong nhiều trường hợp tách phần thân của một forvòng lặp trong một chức năng đứng tự do (trong khi hơi đau) dẫn đến một giải pháp sạch hơn nhiều. Khi làm việc với các bộ sưu tập, xem xét std::for_each, std::transformhoặc std::accumulate. Việc thực hiện nhiều thuật toán trở nên súc tích và rõ ràng khi được thể hiện theo cách này. Chưa kể đến việc cô lập phần thân của vòng lặp thành một hàm / phương thức riêng biệt buộc bạn phải tập trung vào thuật toán, các yêu cầu đầu vào và kết quả của nó.

Nếu bạn đang sử dụng Java, Python, Ruby hoặc thậm chí C ++ 0x , thì bạn nên sử dụng một vòng lặp foreach bộ sưu tập thích hợp . Khi trình biên dịch C ++ thực hiện tính năng này, một số forvòng lặp sẽ biến mất theo các kiểu thảo luận này.


2
"Tuy nhiên, sử dụng một toán tử ít hạn chế hơn là một thành ngữ lập trình phòng thủ rất phổ biến." Điều này tổng hợp nó nhiều hay ít.
James P.

1 cho discussin sự khác biệt về ý định với so với while, forforeach(hoặc equivilant ngôn ngữ)
Kevin Peno

Nói đúng ra, các whilevòng lặp được sử dụng để tiếp tục xử lý cho đến khi một điều kiện cụ thể được không gặp
Alnitak

@Alnitak - D'oh ... Tôi sẽ sửa nó :)
D.Shawley

Tôi đã bị nhầm lẫn bởi hai ý nghĩa có thể có của "ít hạn chế hơn": nó có thể đề cập đến toán tử được khoan dung trong các giá trị mà nó truyền ( <) hoặc toán tử trở nên khoan dung trong các giá trị mà nó thất bại ( !=).
Mateen Ulhaq

4

Sử dụng "ít hơn" là (thường) đúng về mặt ngữ nghĩa, bạn thực sự có nghĩa là đếm ngược cho đến khi ikhông nhỏ hơn 10, vì vậy "ít hơn" truyền đạt rõ ràng ý định của bạn. Sử dụng "không bằng" rõ ràng hoạt động trong hầu hết các trường hợp cuộc gọi, nhưng chuyển tải một ý nghĩa hơi khác nhau. Trong một số trường hợp, đây có thể là những gì bạn cần nhưng theo kinh nghiệm của tôi thì điều này chưa bao giờ xảy ra. Nếu bạn thực sự đã có một trường hợp icó thể nhiều hơn hoặc ít hơn 10 nhưng bạn muốn tiếp tục lặp cho đến khi nó bằng 10, thì mã đó sẽ thực sự cần bình luận rất rõ ràng và có thể được viết tốt hơn với một số cấu trúc khác, chẳng hạn như một whilevòng lặp có lẽ.


2

Một lý do tại sao tôi muốn ủng hộ less thanhơn not equalslà hành động như một người bảo vệ. Trong một số trường hợp hạn chế (lập trình xấu hoặc vệ sinh), not equalscó thể bỏ qua trong khi less thanvẫn có hiệu lực.

Dưới đây là một ví dụ về việc thiếu kiểm tra vệ sinh đã dẫn đến kết quả kỳ lạ: http://www.michaeleisen.org/blog/?p=353


0

Đây là một lý do tại sao bạn có thể thích sử dụng <hơn là !=. Nếu bạn đang sử dụng một ngôn ngữ có phạm vi biến toàn cục, điều gì xảy ra nếu mã khác sửa đổi i? Nếu bạn đang sử dụng <chứ không phải !=, điều tồi tệ nhất xảy ra là việc lặp lại kết thúc nhanh hơn: có thể một số mã khác tăng lên một icách tình cờ và bạn bỏ qua một vài lần lặp trong vòng lặp for. Nhưng điều gì xảy ra nếu bạn lặp từ 0 đến 10 và vòng lặp lên 9 và một số luồng được viết xấu ivì một số lý do kỳ lạ. Sau đó, vòng lặp của bạn kết thúc lần lặp đó và tăng dần iđể giá trị bây giờ là 11. Vì vòng lặp đã bỏ qua điều kiện thoát ( ikhông bao giờ bằng 10), giờ đây nó sẽ lặp lại vô hạn.

Nó không nhất thiết phải là logic loại biến luồng và biến toàn cầu đặc biệt kỳ quặc gây ra điều này. Nó có thể chỉ là bạn đang viết một vòng lặp cần quay lại. Nếu bạn đang đột biến ibên trong vòng lặp và bạn làm hỏng logic của mình, việc có nó để nó có giới hạn trên thay vì !=ít có khả năng khiến bạn rơi vào vòng lặp vô hạn.


3
Tất nhiên, điều này có vẻ như là một đối số hoàn hảo cho - mỗi vòng lặp và một phong cách lập trình chức năng hơn nói chung. Nhưng, tại sao bạn lại muốn làm điều đó khi các biến có thể thay đổi trở nên thú vị hơn nhiều ?!
Tom Morris

3
Tôi không nghĩ đó là một lý do tốt khủng khiếp. Dù bằng cách nào bạn cũng có một lỗi cần được tìm và sửa, nhưng một vòng lặp vô hạn có xu hướng tạo ra một lỗi khá rõ ràng.
ak2

0

Trong thế giới nhúng, đặc biệt là trong môi trường ồn ào, bạn không thể tin tưởng vào RAM nhất thiết phải hoạt động như bình thường. Trong một điều kiện (trong, trong khi, nếu) khi bạn so sánh bằng cách sử dụng '==' hoặc '! =', Bạn luôn gặp rủi ro khi các biến của bạn bỏ qua giá trị quan trọng đó chấm dứt vòng lặp - điều này có thể gây ra hậu quả thảm khốc - Mars Lander hậu quả cấp độ. Sử dụng '<' hoặc '>' trong điều kiện cung cấp thêm một mức độ an toàn để nắm bắt 'những ẩn số chưa biết'.

Trong ví dụ ban đầu, nếu ikhông thể giải thích được một giá trị lớn hơn 10, thì phép so sánh '<' sẽ bắt lỗi ngay lập tức và thoát khỏi vòng lặp, nhưng '! =' Sẽ tiếp tục đếm cho đến khi ivượt qua 0 và quay lại đến 10.


2
Một biến thể liên quan khác tồn tại với mã như for (i=4; i<length; i++) csum+=dat[i];trong đó các gói hợp pháp sẽ luôn có lengthít nhất bốn, nhưng một biến có thể nhận được các gói bị hỏng. Nếu các loại gói khác nhau có các yêu cầu về độ dài khác nhau, người ta có thể xác thực độ dài là một phần của quá trình xử lý khác nhau đối với từng loại gói, nhưng trước tiên hãy xác thực tổng kiểm tra như một phần của logic chung. Nếu một gói dưới độ dài được nhận, thực sự không quan trọng việc tính toán tổng kiểm tra báo cáo "tốt" hay "xấu", nhưng nó không bị sập.
supercat
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.