Mục đích của khối 'if (0)' trong khối if-other là gì?


141

Câu hỏi của tôi là về dòng tôi đã đề cập trong chủ đề và tôi có thể thấy ở nhiều nơi trong mã sản xuất.

Mã tổng thể trông như thế này:

if (0) {
    // Empty braces
} else if (some_fn_call()) {
    // actual code
} else if (some_other_fn_call()) {
    // another actual code
    ...
} else {
    // default case
}

Các ngành khác không liên quan đến câu hỏi của tôi. Tôi đang tự hỏi ý nghĩa của việc đặt if (0)ở đây là gì. Niềng răng trống rỗng, vì vậy tôi không nghĩ rằng nên bình luận một số khối mã. Liệu nó có buộc trình biên dịch thực hiện một số tối ưu hóa hay ý định của nó khác nhau không?

Tôi đã cố gắng tìm kiếm trường hợp rõ ràng này ở đây trên SO và trên internet, nhưng không thành công. Có những câu hỏi tương tự về JavaScript, nhưng không phải C. Có một câu hỏi khác, Điều gì xảy ra khi số 0 được gán trong điều kiện `if`? , nhưng nó thảo luận về phép gán 0 cho một biến, không phải là cách sử dụng 'if (0)'.


2
Câu nói đó dường như không liên quan. Tạo mã lắp ráp có và không có câu lệnh đó và bạn sẽ thấy những gì đang diễn ra dưới mui xe.
haccks

2
Có thể đây là một mã được tạo tự động.
quái dị

Câu trả lời:


91

Đôi khi tôi sử dụng điều này cho đối xứng để tôi có thể di chuyển người khác một else if{cách tự do xung quanh với trình soạn thảo của mình mà không phải bận tâm đến việc đầu tiên if.

Về mặt ngữ nghĩa

if (0) {
    // Empty braces
} else 

một phần không làm gì cả và bạn có thể tin tưởng vào trình tối ưu hóa để xóa nó.


239
Ý kiến ​​cá nhân: Mặc dù đây có thể là mã lý do tại sao nó được viết như vậy, tôi nghĩ đó là một lời biện minh tồi tệ. Mã được đọc thường xuyên hơn so với mã được viết và mã không cần thiết này chỉ làm tăng chi phí phân tích cú pháp cho người đọc.
dùng694733

13
@ user694733: Bạn có thể lập luận rằng if elsetiền tố chung cho tất cả các đường dẫn mã quan trọng sắp xếp các điều kiện độc đáo và giúp quét chúng dễ dàng hơn. (Tuy nhiên, điều đó chủ quan và sẽ phụ thuộc rất nhiều vào những gì thực sự bên trong các điều kiện và khối mã.)
M Oehm

72
Tôi không nghĩ if (0) {..}giới thiệu bất kỳ vấn đề phân tích / khả năng đọc. Bất cứ ai biết một chút về C. Đó không phải là vấn đề rõ ràng. Vấn đề là câu hỏi tiếp theo sau khi đọc nó: "Cái quái gì vậy?" Trừ khi đó là để gỡ lỗi / mục đích tạm thời (nghĩa là, ý định là "kích hoạt" ifkhối đó sau), tôi sẽ ủng hộ loại bỏ hoàn toàn. Về cơ bản "đọc" mã như vậy có thể sẽ gây ra "tạm dừng" không cần thiết cho người đọc mà không có lý do chính đáng. Và đó là một lý do đủ tốt để loại bỏ nó.
PP

77
Có vẻ như nó chắc chắn làm giảm khả năng đọc. Thật tệ khi nó đã gửi lập trình viên đó đến SO để hỏi nó dùng để làm gì. Không phải là một dấu hiệu tốt.
Vectorjohn

26
Ngay cả khi sử dụng mẫu này, tôi cũng không biết liệu bạn có thể "di chuyển else ifxung quanh trình chỉnh sửa mà không phải lo lắng" bởi vì các điều kiện có thể không loại trừ lẫn nhau, trong trường hợp thứ tự có vấn đề. Cá nhân tôi sẽ chỉ sử dụng ifvà thực hiện trả về sớm , trích xuất chuỗi logic thành một chức năng riêng nếu cần thiết.
John Wu

105

Điều này có thể hữu ích nếu có #iftuyên bố, ala

   if (0)
   {
       // Empty block
   }
#if TEST1_ENABLED
   else if (test1())
   {
      action1();
   }
#endif
#if TEST2_ENABLED
   else if (test2())
   {
      action2();
   }
#endif

Vân vân.

Trong trường hợp này, bất kỳ (và tất cả) các bài kiểm tra có thể được #ifloại bỏ và mã sẽ được biên dịch chính xác. Hầu như tất cả các trình biên dịch sẽ loại bỏ if (0) {}một phần. Một trình phát tự động đơn giản có thể tạo mã như thế này, vì mã dễ hơn một chút - nó không phải xem xét riêng khối được kích hoạt đầu tiên.


5
Trong nhiều trường hợp, một if/ else ifchuỗi không được sử dụng nhiều như một cây quyết định, mà là một cấu trúc "hành động theo điều kiện khớp đầu tiên", trong đó điều kiện xảy ra có mức ưu tiên cao nhất không đặc biệt "đặc biệt". Mặc dù tôi không thấy if(0)được sử dụng như một cách để cho phép tất cả các nhánh thực sự có cú pháp nhất quán, tôi thích cú pháp nhất quán mà nó tạo điều kiện.
supercat

1
Nó thậm chí không hữu ích trong trường hợp này bởi vì bạn có thể đạt được hiệu ứng tương tự mà không cần: chỉ cần chia else ifdòng thành hai và đặt bộ bảo vệ tiền xử lý ở giữa.
Konrad Rudolph

1
@KonradRudolph Tôi không theo dõi; bạn sẽ viết nó như thế nào
JiK

1
@JiK Tôi sẽ xóa if (0)chi nhánh và định dạng lại phần còn lại elsenằm trên đường riêng của nó, được bao quanh bởi một người bảo vệ dọc theo dòng #if TEST1_ENABLED && TEST2_ENABLED.
Konrad Rudolph

5
@KonradRudolph thật tốt nếu bạn muốn nhân đôi số lượng lính canh và nhân ba số lượng điều kiện bảo vệ được đề cập, tôi cho rằng.
hobbs

44

Tôi đã thấy một mô hình tương tự được sử dụng trong mã được tạo. Ví dụ, trong SQL, tôi đã thấy các thư viện phát ra wheremệnh đề sau .

where 1 = 1

Điều này có lẽ giúp bạn dễ dàng thêm vào các tiêu chí khác, bởi vì tất cả các tiêu chí bổ sung có thể được andbổ sung thay vì kiểm tra bổ sung để xem đó có phải là tiêu chí đầu tiên hay không.


4
Điều 1=1này cũng "hữu ích" vì bạn luôn có thể thêm wherephía trước, vô điều kiện. Nếu không, bạn phải kiểm tra xem nó có trống không và nếu có thì tránh tạo wheremệnh đề.
Bakuriu

2
Ngoài ra, hầu hết các cơ sở dữ liệu sẽ tự động "xóa" 1=1khỏi WHERE, vì vậy nó không ảnh hưởng đến hiệu suất.
Vụ kiện của Quỹ Monica

7
Điều này có thể chấp nhận được trong một thư viện tự động tạo các truy vấn SQL mà hầu như chưa từng thấy bởi nhóm DevOps. Nó không "chấp nhận được" trong mã cấp cao phải được viết và đọc nhiều lần.
phagio

Đây là cách tiếp cận thực sự tiện dụng khi tạo ra một số loại SQL động với số lượng điều kiện cuối cùng không xác định.
Đội trưởng

1
@freakish thực sự tôi đã viết ngược lại: cú pháp dễ đọc được chấp nhận trong mã được tạo vì rất có thể nó sẽ không bao giờ được đọc, không phải trong mã chức năng cấp cao được duy trì bởi các nhà phát triển.
phagio

44

Như được viết, if (0) {}mệnh đề biên dịch thành không có gì.

Tôi nghi ngờ chức năng của mệnh đề ở đầu thang này là cung cấp một nơi dễ dàng để tạm thời vô hiệu hóa tất cả các chức năng khác cùng một lúc (cho mục đích gỡ lỗi hoặc so sánh) bằng cách thay đổi 0thành một 1hoặc true.


2
Đóng đinh nó Tôi không thể thấy bất kỳ lý do nào khác bên cạnh việc gỡ lỗi.
tfont 23/11/18

16

Tôi không chắc chắn về bất kỳ tối ưu hóa nào, nhưng hai xu của tôi:

Điều này xảy ra do một số sửa đổi mã, trong đó một điều kiện chính đã bị xóa, (hàm gọi trong ifkhối ban đầu , giả sử), nhưng các nhà phát triển / bảo trì

vì vậy thay vì loại bỏ ifkhối liên quan , họ chỉ cần thay đổi điều kiện thành if(0)và chuyển sang.


3
Không phải là if(0)giảm phạm vi bảo hiểm quá?
David Szalai

1
@DavidSzalai Không hoàn toàn - nhiều nhất là nó sẽ giảm 1 (so với 2 lần trước) - nhưng một cú đánh vẫn sẽ được yêu cầu để bảo hiểm, theo sự hiểu biết tốt nhất của tôi.
Sourav Ghosh

15

Đó là mã thối.

Tại một số điểm "nếu" đã làm điều gì đó hữu ích, tình huống đã thay đổi, có thể biến được đánh giá đã bị xóa.

Người đã sửa chữa / thay đổi hệ thống đã làm ít nhất có thể để ảnh hưởng đến logic của hệ thống, vì vậy anh ta chỉ đảm bảo mã sẽ được biên dịch lại. Vì vậy, anh ta để lại "nếu (0)" bởi vì điều đó nhanh chóng và dễ dàng và anh ta không hoàn toàn chắc chắn đó là những gì anh ta muốn làm. Anh ta làm cho hệ thống hoạt động và anh ta không quay lại để sửa nó hoàn toàn.

Sau đó, nhà phát triển tiếp theo xuất hiện và nghĩ rằng nó đã được thực hiện một cách có chủ ý và chỉ nhận xét rằng một phần của mã (vì dù sao nó không được đánh giá), nên lần sau khi mã được chạm vào những bình luận đó sẽ bị xóa.


2
Vâng Đối với mã cổ, hãy thực hiện một thay đổi loại bỏ mã chết tại một thời điểm. Tôi không thể đếm số lần tôi đã trải qua một vụ đâm chém dữ dội vào mã "chết" chỉ để phát hiện ra có một số tác dụng phụ kỳ quái mà việc chém và đốt bị bỏ lỡ.
Julie ở Austin

15

Một khả năng chưa được đề cập: if (0) {đường dây có thể cung cấp một điểm thuận tiện cho điểm dừng.

Việc gỡ lỗi thường được thực hiện trên mã không được tối ưu hóa để kiểm tra luôn sai sẽ xuất hiện và có thể đặt điểm dừng trên đó. Khi được biên dịch để sản xuất, dòng mã sẽ được tối ưu hóa. Dòng dường như vô dụng cung cấp chức năng cho các bản dựng phát triển và thử nghiệm mà không ảnh hưởng đến các bản dựng phát hành.

Có những gợi ý tốt khác ở trên là tốt; cách duy nhất để thực sự biết mục đích là gì, là theo dõi tác giả và hỏi. Hệ thống kiểm soát mã nguồn của bạn có thể giúp với điều đó. (Tìm blamechức năng -type.)


9

Tôi đã thấy các khối mã không thể truy cập trong JavaScript được mở rộng trước đã được tạo bằng ngôn ngữ tạo khuôn mẫu.

Chẳng hạn, mã bạn đang đọc có thể đã được dán từ một máy chủ đã đánh giá trước điều kiện đầu tiên mà tại thời điểm đó chỉ dựa vào một biến chỉ có sẵn ở phía máy chủ.

if ( ${requestIsNotHttps} ){ ... }else if( ...

mà một khi hàng rào được biên soạn trước:

if ( 0 ){ ... }else if ( ...

hy vọng điều này sẽ giúp bạn tương đối hóa hoạt động bàn phím thấp tiềm năng của kỷ nguyên tiền mã hóa tái chế mà tôi thể hiện sự nhiệt tình!


1
Tôi đồng ý, trong thời đại tự động hóa phổ biến, chúng ta nên dựa vào mã tự phát nhiều hơn, vì nó cho phép chúng ta dành nhiều thời gian hơn cho những thứ thực tế. Nhưng bây giờ, điểm quan tâm chính xác của tôi là làm thế nào mọi thứ này được kiến ​​trúc dưới mui xe.
Zzaponka

8

Cấu trúc đó cũng có thể được sử dụng trong C để thực hiện lập trình chung với loại an toàn, dựa trên thực tế là mã không thể truy cập vẫn được trình biên dịch kiểm tra:

// this is a generic unsafe function, that will call fun(arg) at a later time
void defer(void *fun, void *arg);

// this is a macro that makes it safer, by checking the argument
// matches the function signature
#define DEFER(f, arg) \
   if(0) f(arg); \              // never actually called, but compile-time checked
   else defer(f, (void *)arg);  // do the unsafe call after safety check

void myfunction(int *p);

DEFER(myfunction, 42);     // compile error
int *b;
DEFER(myfunction, b);      // compiles OK

6

Tôi nghĩ rằng đó chỉ là mã xấu. Viết một ví dụ nhanh trong Compiler Explorer, chúng tôi thấy rằng trong cả gcc và clang, không có mã nào được tạo cho if (0)khối, ngay cả khi tối ưu hóa hoàn toàn bị vô hiệu hóa:

https://godbolt.org/z/PETIks

Chơi xung quanh với việc loại bỏ các if (0)nguyên nhân không có thay đổi đối với mã được tạo, vì vậy tôi kết luận rằng đây không phải là một tối ưu hóa.

Có thể đã từng có một cái gì đó trong ifkhối trên cùng mà sau đó đã bị xóa. Nói tóm lại, có vẻ như loại bỏ nó sẽ khiến cùng một mã được tạo ra, vì vậy hãy thoải mái làm điều đó.


6

Như đã nói, số 0 được đánh giá là sai và nhánh có thể sẽ được trình biên dịch tối ưu hóa.

Tôi cũng đã thấy điều này trước đây trong mã nơi có một tính năng mới được thêm vào và công tắc kill là cần thiết (nếu có vấn đề gì đó với tính năng bạn có thể tắt nó đi) và một thời gian sau khi công tắc kill bị loại bỏ lập trình viên cũng không xóa chi nhánh, vd

if (feature_a_active()) {
    use_feature_a();
} else if (some_fn()) {
   ...

đã trở thành

if (0) {
   // empty
} else if (some_fn()) {
   ...

1

Nó giúp gỡ lỗi khối này chỉ đặt nếu khối 1. Điều này vô hiệu hóa tất cả nếu chức năng khối khác. Và chúng ta cũng có thể mở rộng khối if khác.


1
    Actually according to my opinion, if we put any variable for checking inside
    e.g:-
public static void main(string args[])
{
        var status;
        var empList=_unitofWork.EmpRepository.Get(con=>con.isRetired==true);
        //some code logic 
        if(empList.count>0)
        {
          status=true;
        }
        if(status)
        {
         //do something
        }
        else
        {
        //do something else
        }
}
     if then its dynamically get the value in run time and invoke the logic inside it, else its simply extra line of code i guess.

    Anybody have any depth knowledge why this thing is used....or agree with me.
    kindly respond. 

1

Câu trả lời của @ PSkocik là tốt, nhưng tôi thêm hai xu của mình. Không chắc chắn nếu tôi nên làm điều này như một bình luận, hoặc như một câu trả lời; chọn cái sau, bởi vì IMHO đáng để người khác nhìn thấy, trong khi các bình luận thường vô hình.

Tôi không chỉ thỉnh thoảng sử dụng

if(0) {
   //deliberately left empty
} else if( cond1 ) {
   //deliberately left empty
} else if( cond2 ) {
   //deliberately left empty
...
} else {
   // no conditions matched
}

Nhưng tôi cũng thỉnh thoảng làm

if( 1 
    && cond1 
    && cond2
    ...
    && condN
) {

hoặc là

if( 0 
    || cond1 
    || cond2
    ...
    || condN
) {

cho các điều kiện phức tạp. Vì những lý do tương tự - dễ dàng chỉnh sửa hơn, #ifdef, v.v.

Đối với vấn đề đó, trong Perl tôi sẽ làm

@array = (  
    elem1,
    elem2,
    ...
    elem1,
) {
  • lưu ý dấu phẩy ở cuối danh sách. Tôi quên nếu dấu phẩy là dấu phân cách hoặc dấu phân cách trong danh sách C và C ++. IMHO đây là một điều chúng tôi đã học được: [ Dấu phẩy trong Perl có phải là một thực tiễn xấu không? dấu phẩy] là một điều tốt. Giống như bất kỳ ký hiệu mới nào, phải mất một thời gian để làm quen.

Tôi so sánh if(0)mã với lisp

(cond   (test1    action1)
   (test2    action2)
   ...
   (testn   actionn))

mà, bạn đoán nó, tôi có thể thụt lề

(cond   
   (test1    action1)
   (test2    action2)
   ...
   (testn   actionn)
)

Đôi khi tôi đã cố gắng tưởng tượng một cú pháp dễ đọc hơn của con người cho việc này có thể trông như thế nào.

Có lẽ

IF
:: cond1 THEN code1
:: cond2 THEN code2
...
:: condN THEN codeN
FI

lấy cảm hứng từ [ https://en.wikipedia.org/wiki/Guarded_Command_L Language# Selection:_if[[Guarded Language Language] của Dikstra .

Nhưng cú pháp này ngụ ý rằng các điều kiện được đánh giá song song, trong khi if...else-ifngụ ý đánh giá tuần tự và ưu tiên các điều kiện.

Tôi bắt đầu làm những việc như thế này khi viết các chương trình tạo ra các chương trình khác, nơi nó đặc biệt thuận tiện.

Trong khi chúng ta đang ở đó, khi viết RTL bằng iHDL cũ của Intel, tôi đã mã hóa những thứ như

   IF 0 THEN /*nothing*/
   **FORC i FROM 1 TO 10 DOC** 
   ELSE IF signal%i% THEN    
      // stuff to do if signal%i% is active
   **ENDC** 
   ELSE   
      // nothing matched 
   ENDIF

trong đó FORC..DOC..ENDCcấu trúc vòng lặp tiền xử lý macro, mở rộng thành

   IF 0 THEN /*nothing*/
   ELSE IF signal1 THEN    
      // stuff to do if signal1 is active
   ELSE IF signal2 THEN    
      // stuff to do if signal2 is active
   ...
   ELSE IF signal100 THEN    
      // stuff to do if signal100 is active
   ELSE   
      // nothing matched 
   ENDIF

Đây là phép gán đơn, không bắt buộc, mã, vì vậy việc đặt biến trạng thái là không được phép, nếu bạn cần thực hiện những việc như tìm bit set đầu tiên.

   IF 0 THEN /*nothing*/
   ELSE IF signal1 THEN    
      found := 1
   ELSE IF signal2 THEN    
      found := 2
   ...
   ELSE IF signal100 THEN    
      found := 100
   ELSE   
      // nothing matched 
   ENDIF

Nghĩ lại thì, đây có thể là nơi đầu tiên tôi gặp phải những công trình như vậy.

BTW, sự phản đối mà một số người phải theo kiểu if (0) - rằng các điều kiện khác nếu phụ thuộc tuần tự và không thể được sắp xếp lại một cách tùy tiện - không áp dụng cho logic AND và OR và XOR trong RTL - nhưng áp dụng cho ngắn- mạch && và ||.


-1

Tôi đã thấy điều này được sử dụng để xử lý lỗi, ví dụ

if(0){
lable1:
   //do something
}
if(0){
lable2:
   //do something
}
.
.
and so on.

if(condition_fails)
   goto lable1;

Điều này có thể hữu ích khi goto được sử dụng để quản lý lỗi, các câu lệnh chỉ được thực thi khi xảy ra lỗi. Tôi đã thấy điều này trong mã C rất cũ (nơi các đối số hàm được viết bên ngoài '()'), đừng nghĩ rằng bất cứ ai cũng làm theo điều này ngay bây giờ.


-2

Tôi đã thấy điều này một vài lần, tôi nghĩ lý do rất có thể là nó đang đánh giá một cái gì đó trong một phiên bản / nhánh mã cũ hơn hoặc khác nhau, hoặc có thể để gỡ lỗi, và thay đổi nó thành if(0)một cách lười biếng để loại bỏ bất cứ thứ gì ở đó .

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.