2010-03-04 15 views
20

Bản sao có thể xảy ra:
What’s the use of do while(0) when we define a macro?
Why are there sometimes meaningless do/while and if/else statements in C/C++ macros?
C multi-line macro: do/while(0) vs scope block"do {...} trong khi (0)" làm gì chính xác trong mã hạt nhân?

Tôi đã thấy rất nhiều tập quán như thế này, trước đây tôi dù rằng các lập trình viên muốn thoát ra khỏi một khối mã dễ dàng. Tại sao chúng ta cần một vòng lặp {...} trong khi (0) ở đây? Có phải chúng ta đang cố nói cho trình biên dịch một cái gì đó?

Ví dụ trong Linux kernel 2.6.25, bao gồm/asm-ia64/system.h

/* 
* - clearing psr.i is implicitly serialized (visible by next insn) 
* - setting psr.i requires data serialization 
* - we need a stop-bit before reading PSR because we sometimes 
* write a floating-point register right before reading the PSR 
* and that writes to PSR.mfl 
*/ 
#define __local_irq_save(x)   \ 
do {     \ 
    ia64_stop();    \ 
    (x) = ia64_getreg(_IA64_REG_PSR); \ 
    ia64_stop();    \ 
    ia64_rsm(IA64_PSR_I);   \ 
} while (0) 
+0

Tôi nghĩ bạn đúng. Điều đó tạo ra khối mà bạn có thể thoát ra. Ngoài ra nó tạo ra một khung khác trên stack, nhưng trong hầu hết các trường hợp nó sẽ chỉ được tối ưu hóa. Để biết thêm manh mối, hãy xem các định nghĩa của ia64_ * Chúng có thể là các macro có các câu lệnh ngắt hoặc một số kiểu nhạo báng khác. – Vlad

+2

http://stackoverflow.com/questions/1067226/c-multi-line-macro-do-while0-vs-scope-block –

+0

Bạn có thể làm tất cả hoặc bạn không có –

Trả lời

2

Hình như nó ở đó chỉ dành riêng cho Phạm vi. Nó tương tự như:

if (true) 
{ 
    // Do stuff. 
} 

chỉnh sửa

Tôi không nhìn thấy nó trong ví dụ của bạn, nhưng nó có thể là một trong những chức năng cuộc gọi thực sự là một vĩ mô, trong trường hợp này có một sự khác biệt quan trọng giữa do/while (0) và if (true), cái mà trước đây cho phép continuebreak.

+0

Nếu nó chỉ dành cho phạm vi, tại sao thậm chí có 'làm' và 'trong khi (0)' hoặc trong trường hợp của câu trả lời này 'nếu đúng)'? Tại sao không chỉ để mở và đóng niềng răng xoăn đứng trên của riêng mình? – semaj

+0

Câu trả lời là nó không * chỉ * cho phạm vi. AndreyT và những người khác đã giải thích phần còn lại của nó. –

23

Luôn được sử dụng trong các macro để dấu chấm phẩy được yêu cầu sau khi gọi, giống như khi gọi một hàm thông thường.

Trong ví dụ của bạn, bạn phải viết

__local_irq_save(1); 

khi

__local_irq_save(1) 

sẽ cho kết quả trong một lỗi về dấu chấm phẩy thiếu. Điều này sẽ không xảy ra nếu không có thời gian ở đó. Nếu nó chỉ là về phạm vi, một cặp ngoặc nhọn đơn giản sẽ đủ.

+0

+1 Đó là giải thích tốt hơn. –

+0

Hấp dẫn. Đó là một mẹo tiện dụng! – Toji

+0

Hấp dẫn, loại. Tôi muốn giới thiệu một chức năng nội tuyến trên một vĩ mô như vậy bất cứ lúc nào (nếu bạn đang sử dụng C + +) mặc dù, mà được bạn yêu cầu dấu chấm phẩy miễn phí :) – OregonGhost

22

Nó cho phép mã để xuất hiện ở đây:

if(a) __local_irq_save(x); else ...; 

// -> if(a) do { .. } while(0); else ...; 

Nếu họ chỉ đơn giản là sử dụng một { .. } bạn sẽ nhận được

if(a) { ... }; else ...; 

Các khác sẽ không thuộc về bất kỳ if nữa, bởi vì dấu chấm phẩy sẽ là tuyên bố tiếp theo và tách riêng số else khỏi tiền tố if. Một lỗi biên dịch sẽ xảy ra.

+0

Cũng là một lý do hợp lệ. Mặt khác, tôi luôn luôn sử dụng các dấu ngoặc nhọn cho các câu lệnh luồng điều khiển để điều này không thể xảy ra. Do đó, lỗi trình biên dịch sẽ được chấp nhận đối với tôi. Sẽ tệ hơn nếu người khác bị tách khỏi if nếu không có * một lỗi biên dịch;) – OregonGhost

+0

OregonGhost: Không phải lúc nào cũng có lỗi cú pháp. 'if (được phép) nếu (! Thích hợp) __set_error (NOT_RIGHT_NOW); else __do_root_action (WIN); ' Với macro' __set_error' sử dụng 'do {...} trong khi (0)', điều này có tác dụng, nếu bạn chỉ sử dụng '{...}' thì người khác thực sự được gắn vào ' nếu (cho phép) 'thay vì' if (! thích hợp) '. Rất tiếc. –

+0

@Michael Speer: Không đúng sự thật. Nếu '__set_error' sử dụng' {} ', thì'; 'sau' __set_error' sẽ chấm dứt cả 'if'-s và' else' sẽ trở thành mồ côi - lỗi cú pháp. Tôi đã nghe về vấn đề tiềm ẩn với 'else' liên quan đến sai, nhưng tôi không thể đưa ra một ví dụ thích hợp. Có lẽ nó không thực sự có thể, chỉ là một huyền thoại đô thị. Bất kỳ ai? – AnT

11

Mục đích của việc xây dựng do{ ... } while(0) là chuyển một nhóm câu lệnh thành một câu lệnh ghép nối đơn lẻ có thể được chấm dứt bằng ;. Bạn thấy đấy, trong ngôn ngữ C, cấu trúc do/while có một thuộc tính kỳ lạ và bất thường: mặc dù nó "hoạt động" như một câu lệnh ghép, nó mong đợi một kết quả là ; ở cuối. Không có cấu trúc hợp chất nào khác trong C có thuộc tính này.

Bởi vì tài sản này, bạn có thể sử dụng do/while để viết macro đa tuyên bố, có thể được an toàn sử dụng như chức năng "bình thường" mà không lo lắng gì bên trong vĩ mô, như trong ví dụ sau

if (/* some condition */) 
    __local_irq_save(x); /* <- we can safely put `;` here */ 
else 
    /* whatever */; 
5

Các câu trả lời đã được đưa ra (vì vậy macro bắt buộc một số ; khi được gọi), nhưng sử dụng loại câu lệnh mà tôi đã thấy: nó cho phép ngắt được gọi ở bất kỳ đâu trong "vòng lặp", kết thúc sớm nếu cần. Về cơ bản một "goto" mà các lập trình viên của bạn sẽ không giết bạn.

do { 
    int i = do_something(); 
    if(i == 0) { break; } // Skips the remainder of the logic 
    do_something_else(); 
} while(0); 

Lưu ý rằng điều này vẫn còn khá khó hiểu, vì vậy tôi không khuyến khích việc sử dụng nó.

2

Nó sử dụng hành vi macro như lệnh thực hoặc lệnh gọi hàm.

Một tuyên bố được một trong hai { expression-list } hoặc expression; để đặt ra một vấn đề khi định nghĩa các macro mà cần nhiều hơn một biểu hiện, bởi vì nếu bạn sử dụng { } sau đó một lỗi cú pháp sẽ xảy ra nếu người gọi của vĩ mô khá hợp lý cho biết thêm một ; trước một người khác.

if(whatever) 
    f(x); 
else 
    f(y); 

Nếu một vĩ mô đơn lẻ, tiền phạt, nhưng nếu vĩ mô và điều gì đó phức tạp thì sao? Bạn kết thúc với if(...) { s1; s2; }; else ... và điều đó không hoạt động.

Vì vậy, người viết macro phải sau đó biến nó thành một hàm thực, quấn cấu trúc trong một câu lệnh đơn lẻ hoặc sử dụng phần mở rộng gnu.

Mẫu do .. while(0) là phương pháp "bọc cấu trúc".

Các vấn đề liên quan