2012-05-21 32 views
10

CáC++ mã C sau biên dịch và hoạt động như các lập trình viên có ý định trên GCC (4.0.4)macro Preprocessor như tham số cho macro khác

#define FOO(x,y,z) ((x)*(y)*(z)) 
#define BAR(x) FOO(x,1) 
#define BAZ 3,7 

int main() 
{ 
    return BAR(BAZ); /* interpreted as return ((3)*(7)*(1)); */ 
} 

Tuy nhiên, các macro gây ra một lỗi trên Microsoft Visual C++ nhanh 2010:

main.cpp (7): C4003 cảnh báo: không đủ các thông số thực tế cho macro 'foo'
main.cpp (7): lỗi C2059: lỗi cú pháp: ')'

Vấn đề có vẻ là trình biên dịch Microsoft, trong khi xử lý macro BAR bên trong, không mở rộng macro BAZ thành các tham số có thể được sử dụng làm hai tham số riêng biệt cho macro FOO.

Theo tiêu chuẩn, trình biên dịch xử lý tình huống chính xác?

+0

Có vẻ như những gì bạn đang thực sự tìm kiếm là [Macro biến thể] (http://en.wikipedia.org/wiki/Variadic_macro). – leftaroundabout

+3

@leftaroundabout nó không có vẻ như ông là ... –

+3

@iammilind: Những gì còn thiếu trong chương 16 của tiêu chuẩn? Làm thế nào nó không phải là một tiêu chuẩn 'thực'? –

Trả lời

12

Theo 16.3.4 của tiêu chuẩn ISO/IEC 14882: 2003 (C++ standard) mở rộng vĩ mô được thực hiện như sau:

  1. Macro gọi được thay thế bằng danh sách thay thế của vĩ mô (cơ thể), nơi mỗi tên tham số (trừ khi nó bị ảnh hưởng bởi # hoặC##) được thay thế bằng một macro mở rộng hoàn chỉnh của đối số tương ứng được chỉ định trong lời gọi macro.
  2. Kết quả của bước 1 là được quét lại. Nếu có nhiều lời mời macro hơn trong nó (ngoại trừ những người đã mở rộng nhận văn bản đang được xem xét), chúng được mở rộng theo cùng một thủ tục đệ quy.

Trình tự các bước này cho các mã mà bạn chỉ định là:

  1. BAR(BAZ)
  2. FOO(3,7,1)
  3. ((3)*(7)*(1))

Vì vậy, GCC là đúng, và VC thì không. Nhưng lỗi mà VC phàn nàn là FOO có 3 đối số và BAR chỉ định 2 trong số chúng. VC dường như cố gắng để bắt lỗi càng sớm càng tốt và đi một chút quá xa trong đó.

+1

Tôi không hiểu cách thuật toán mà bạn đã đưa ra tương ứng với hành vi GCC. Nếu tôi đọc nó một cách chính xác, thuật toán đi như sau: 'BAR (BAZ)' là một lời gọi của 'BAR' với đối số' BAZ', do đó được thay thế bằng 'FOO (BAZ, 1)'. Điều này bây giờ được quét lại. Macro đầu tiên mà nó tìm thấy là 'FOO', vì vậy bây giờ nó cố gắng mở rộng' FOO' với các đối số 'BAZ' và' 1'. Đây không phải là đủ đối số, do đó quá trình xử lý trước không thành công. Tại sao việc quét lại 'FOO (BAZ, 1)' mở rộng 'BAZ' trước, khi quét' BAR (BAZ) 'mở rộng' BAR' trước? – Mankarse

+0

@Mankarse Cảm ơn, nó thực sự không đủ rõ ràng. Đã sửa. –

+0

Cảm ơn bạn đã giải thích rõ ràng và đầy đủ. Tôi đã học được rất nhiều. – Mankarse

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