Macro là bản sao / dán các đoạn văn bản mà bộ xử lý trước sẽ đặt vào mã chính hãng; tác giả của macro hy vọng sự thay thế sẽ tạo ra mã hợp lệ.
Có ba "mẹo" tốt để thành công trong đó:
Giúp macro hoạt động như mã chính hãng
Mã bình thường thường được kết thúc bằng dấu chấm phẩy. Nếu người dùng xem mã không cần ...
doSomething(1) ;
DO_SOMETHING_ELSE(2) // <== Hey? What's this?
doSomethingElseAgain(3) ;
Điều này có nghĩa là người dùng hy vọng trình biên dịch sẽ tạo ra lỗi nếu không có dấu chấm phẩy.
Nhưng lý do thực sự tốt là vào một lúc nào đó, tác giả của macro có thể sẽ cần thay thế macro bằng một hàm chính hãng (có thể được nội tuyến). Vì vậy, vĩ mô nên thực sự hành xử như một.
Vì vậy, chúng ta nên có một macro cần bán đại tràng.
Tạo mã hợp lệ
Như được hiển thị trong câu trả lời của jfm3, đôi khi macro chứa nhiều hơn một lệnh. Và nếu macro được sử dụng bên trong câu lệnh if, điều này sẽ có vấn đề:
if(bIsOk)
MY_MACRO(42) ;
Macro này có thể được mở rộng như:
#define MY_MACRO(x) f(x) ; g(x)
if(bIsOk)
f(42) ; g(42) ; // was MY_MACRO(42) ;
Các g
chức năng sẽ được thực hiện không phụ thuộc vào giá trị của bIsOk
.
Điều này có nghĩa là chúng ta phải thêm một phạm vi vào macro:
#define MY_MACRO(x) { f(x) ; g(x) ; }
if(bIsOk)
{ f(42) ; g(42) ; } ; // was MY_MACRO(42) ;
Tạo mã hợp lệ 2
Nếu macro là một cái gì đó như:
#define MY_MACRO(x) int i = x + 1 ; f(i) ;
Chúng ta có thể có một vấn đề khác trong đoạn mã sau:
void doSomething()
{
int i = 25 ;
MY_MACRO(32) ;
}
Bởi vì nó sẽ mở rộng như:
void doSomething()
{
int i = 25 ;
int i = 32 + 1 ; f(i) ; ; // was MY_MACRO(32) ;
}
Mã này sẽ không được biên dịch, tất nhiên. Vì vậy, một lần nữa, giải pháp đang sử dụng một phạm vi:
#define MY_MACRO(x) { int i = x + 1 ; f(i) ; }
void doSomething()
{
int i = 25 ;
{ int i = 32 + 1 ; f(i) ; } ; // was MY_MACRO(32) ;
}
Mã hoạt động chính xác một lần nữa.
Kết hợp hiệu ứng bán đại tràng + phạm vi?
Có một thành ngữ C / C ++ tạo ra hiệu ứng này: Vòng lặp do / while:
do
{
// code
}
while(false) ;
Do / while có thể tạo ra một phạm vi, do đó gói gọn mã của macro và cần một dấu chấm phẩy cuối cùng, do đó mở rộng thành mã cần một mã.
Tiền thưởng?
Trình biên dịch C ++ sẽ tối ưu hóa vòng lặp do / while, vì thực tế hậu điều kiện của nó là sai được biết tại thời điểm biên dịch. Điều này có nghĩa là một macro như:
#define MY_MACRO(x) \
do \
{ \
const int i = x + 1 ; \
f(i) ; g(i) ; \
} \
while(false)
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
MY_MACRO(42) ;
// Etc.
}
sẽ mở rộng chính xác như
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
do
{
const int i = 42 + 1 ; // was MY_MACRO(42) ;
f(i) ; g(i) ;
}
while(false) ;
// Etc.
}
và sau đó được biên dịch và tối ưu hóa đi như
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
{
f(43) ; g(43) ;
}
// Etc.
}
void
loại ở cuối ... như ((void) 0) .