Chính xác thì khối #if 0… #endif làm gì?


124

Trong C / C ++

Điều gì xảy ra với mã được đặt giữa một #if 0/ #endifkhối?

#if 0

//Code goes here

#endif

Có phải mã chỉ bị bỏ qua và do đó không được thực thi?


17
Đây là một kỹ thuật được sử dụng để nhận xét số lượng lớn mã hoặc cho phép kiểm tra việc bao gồm các khối mã. Nếu không có tính năng này, người ta sẽ phải đặt tiền tố mỗi dòng bằng //hoặc bắt đầu phần bằng /*và kết thúc phần bằng */. Vấn đề với các kỹ thuật thứ hai là nhận xét không lồng vào nhau, vì vậy nhà phát triển phải kiểm tra và xử lý bất kỳ phần nào */giữa đầu và cuối.
Thomas Matthews

Câu trả lời:


141

Nó không chỉ không được thực thi mà thậm chí còn không được biên dịch.

#iflà một lệnh tiền xử lý, được đánh giá trước bước biên dịch thực sự. Mã bên trong khối đó không xuất hiện trong tệp nhị phân đã biên dịch.

Nó thường được sử dụng để xóa tạm thời các đoạn mã với ý định bật lại chúng sau này.


1
Điều này đúng với bất kỳ loại nhận xét nào. Sự khác biệt quan trọng là làm tổ.
Samy Bencherif

73

Nó giống hệt với việc bình luận khối, ngoại trừ một điểm khác biệt quan trọng: Lồng không phải là một vấn đề. Hãy xem xét mã này:

foo();
bar(x, y); /* x must not be NULL */
baz();

Nếu tôi muốn bình luận nó ra, tôi có thể thử:

/*
foo();
bar(x, y); /* x must not be NULL */
baz();
*/

Bzzt. Lỗi cú pháp! Tại sao? Bởi vì các bình luận khối không lồng vào nhau, và do đó (như bạn có thể thấy từ tô sáng cú pháp của SO) */sau từ "NULL" kết thúc bình luận, khiến bazcuộc gọi không nhận xét ra ngoài và */sau bazmột lỗi cú pháp. Mặt khác:

#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif

Hoạt động để bình luận ra toàn bộ sự việc. Và các #if 0s sẽ lồng vào nhau, như vậy:

#if 0
pre_foo();
#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif
quux();
#endif

Mặc dù tất nhiên điều này có thể hơi khó hiểu và trở thành vấn đề đau đầu về bảo trì nếu không được nhận xét đúng cách.


5
Chỉ cần lưu ý rằng mã bên trong #if phải chính xác về mặt từ vựng (trái ngược với nhận xét) và các lệnh tiền xử lý vẫn còn hiệu lực (ditto).
jpalecek

@David: Nó không đúng về mặt từ vựng, nhưng nó vẫn sẽ được biên dịch. Vì vậy, mã không cần phải chính xác về mặt từ vựng.
Dennis Zickefoose

1
@Dennis, tôi nhận được foo.c:3: unterminated string or character constanttừ gcc, bạn đang sử dụng cái gì vậy?
David X

18

Nó vĩnh viễn bình luận ra mã đó để trình biên dịch sẽ không bao giờ biên dịch nó.

Người lập trình sau đó có thể thay đổi #ifdef để mã đó được biên dịch trong chương trình nếu anh ta muốn.

Nó chính xác như mã không tồn tại.


15

Chính xác thì khối #if 0… #endif làm gì?

Nó cho bạn biết rằng tác giả rõ ràng là chưa bao giờ nghe nói về hệ thống kiểm soát phiên bản. Đến lượt nó, nó yêu cầu bạn chạy càng xa càng tốt…


12

Tôi muốn bổ sung thêm cho #elsetrường hợp:

#if 0
   /* Code here will NOT be complied. */
#else
   /* Code will be compiled. */
#endif


#if 1
   /* Code will be complied. */
#else
   /* Code will NOT be compiled. */
#endif

7

Khi bộ xử lý tiền xử lý thấy # nếu nó sẽ kiểm tra xem mã thông báo tiếp theo có giá trị khác 0 hay không. Nếu có, nó sẽ giữ mã cho trình biên dịch. Nếu không, nó sẽ loại bỏ mã đó để trình biên dịch không bao giờ nhìn thấy nó.

Nếu ai đó nói #if 0, họ đang bình luận hiệu quả về mã nên nó sẽ không bao giờ được biên dịch. Bạn có thể nghĩ về điều này giống như thể họ đã đặt / * ... * / xung quanh nó. Nó không hoàn toàn giống nhau, nhưng nó có tác dụng tương tự.

Nếu bạn muốn hiểu những gì đã xảy ra một cách chi tiết, bạn có thể thường xuyên xem. Nhiều trình biên dịch sẽ cho phép bạn xem các tệp sau khi bộ xử lý trước đã chạy. Ví dụ, trên Visual C ++, lệnh switch / P sẽ thực thi bộ tiền xử lý và đưa kết quả vào tệp .i.


Không hẳn. Bộ tiền xử lý phân tích cú pháp theo dòng thay vì mã thông báo. Theo giải thích của bạn, sẽ không thể nói ví dụ như #if WIN32 || __CYGWIN__nhưng điều này không hoạt động như mong đợi.
Ben Voigt

Tôi đã đơn giản hóa. Nếu có hoặc, nó sẽ kiểm tra xem một trong hai mã thông báo có phải là khác 0 hay không. Tương tự như vậy nếu có và nó sẽ kiểm tra xem cả hai có khác không.
Steve Rowe

3

Các dòng bắt đầu bằng a #là các chỉ thị tiền xử lý . #if 0 [...] #endifcác khối không đến được trình biên dịch và sẽ không tạo ra mã máy.

Bạn có thể chứng minh điều gì xảy ra với bộ tiền xử lý bằng tệp nguồn ifdef.cxx:

#if 0
This code will not be compiled
#else
int i = 0;
#endif

Đang chạy gcc -E ifdef.cxxsẽ hiển thị cho bạn những gì được biên dịch.

Bạn có thể chọn sử dụng cơ chế này để ngăn chặn một khối mã được biên dịch trong chu kỳ phát triển, nhưng có thể bạn sẽ không muốn kiểm tra nó trong phần kiểm soát nguồn của mình vì nó chỉ làm tăng thêm lỗi cho mã của bạn và làm giảm khả năng đọc. Nếu đó là một đoạn mã lịch sử đã được nhận xét, thì nó nên được loại bỏ: kiểm soát nguồn chứa lịch sử, phải không?

Ngoài ra, câu trả lời có thể giống nhau cho cả CC ++ nhưng không có ngôn ngữ nào được gọi là C / C ++ và bạn không phải là một thói quen tốt khi đề cập đến một ngôn ngữ như vậy.


4
Có gì sai khi nói C / C ++ là viết tắt của "C hoặc C ++"? Bạn có thực sự nghĩ rằng có ai đó sẽ bối rối khi nghĩ rằng có một ngôn ngữ gọi là "C / C ++" không?
Christopher Barber

1
@Chris: Mọi người liên tục đặt những câu hỏi như "Làm cách nào để thực hiện X trong C / C ++?" Đó là một câu hỏi vô nghĩa; bạn đang viết mã bằng cái này hay cái khác, và nếu bạn vẫn chưa chọn, bạn nên nói rõ thực tế đó. Vì vậy, có, mọi người đang bối rối về việc có một ngôn ngữ được gọi là "C / C ++"
Dennis Zickefoose

1
Thật là một tuyên bố vô nghĩa! Có hàng ngàn câu hỏi có câu trả lời liên quan đến cả C và C ++. Hãy nhớ rằng đây là một trang web để đặt câu hỏi. Chỉ vì bạn đang hỏi một câu hỏi chung chung không có nghĩa là bạn không biết mình đang sử dụng ngôn ngữ nào. Nếu bạn nghi ngờ trường hợp đó, như trong câu hỏi này, việc chỉ định C hoặc C ++ sẽ giúp ích như thế nào? Bạn có nghĩ rằng sẽ hữu ích nếu mọi câu hỏi có thể áp dụng cho C hoặc C ++ được hỏi hai lần?
Christopher Barber

@Christopher: Bạn nói đúng, có rất nhiều câu hỏi mà câu trả lời cũng liên quan đến C, C ++ và Objective-C (đây là một trong số chúng). Stack Overflow có một hệ thống gắn thẻ tiện dụng để biểu thị câu hỏi thuộc về ngôn ngữ nào. Như @Dennis đã đề cập, SO (và các diễn đàn lập trình khác [fora?]) Có (quá) nhiều người nhầm lẫn về việc phân định giữa C và các ngôn ngữ có nguồn gốc từ C khác, những người gọi các ngôn ngữ này thay thế cho nhau là C / C ++. khó trả lời câu hỏi bằng ngôn ngữ thích hợp.
Johnsyweb

2

Không hẳn

int main(void)
{
   #if 0
     the apostrophe ' causes a warning
   #endif
   return 0;
}

Nó hiển thị "tc: 4: 19: warning: thiếu ký tự" terminating "với gcc 4.2.4


2
Cảnh báo này được tạo bởi bộ tiền xử lý, không phải bộ biên dịch. Trình biên dịch chỉ có thể xem: # 1 "tc" # 1 "<built-in>" # 1 "<command-line>" # 1 "tc" int main (void) {return 0; }
Johnsyweb

0

Đó là một cách bình luận rẻ tiền, nhưng tôi nghi ngờ rằng nó có thể có khả năng gỡ lỗi. Ví dụ: giả sử bạn có một bản dựng xuất ra các giá trị cho một tệp. Bạn có thể không muốn điều đó trong phiên bản cuối cùng để bạn có thể sử dụng #if 0 ... #endif.

Ngoài ra, tôi nghi ngờ một cách tốt hơn để làm điều đó cho mục đích gỡ lỗi sẽ là:

#ifdef DEBUG
// output to file
#endif

Bạn có thể làm điều gì đó như vậy và nó có thể có ý nghĩa hơn và tất cả những gì bạn phải làm là xác định GỠ LỖI để xem kết quả.

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.