2011-01-27 45 views
12

Tôi đoán hầu hết các bạn đã từng làm việc với C/C++ đều có trực giác về cách thức xử lý tiền xử lý (nhiều hay ít). Tôi nghĩ như vậy cho đến ngày hôm nay, nhưng trực giác của tôi đã được chứng minh là sai. Đây là câu chuyện:(Lạ?) Hành vi tiền xử lý GCC

Hôm nay tôi đã thử một cái gì đó, nhưng tôi không thể giải thích kết quả. Trước hết hãy xem xét mã sau:

#define A B 
#define B A 

A 
B 

Điều gì sẽ xảy ra? Vâng, kết quả sau khi biên dịch nó với cờ -E là:

A 
B 

Vâng, ok, có thể không phải là điều mọi người mong đợi, nhưng điều đó là dễ hiểu. Tôi đoán rằng các bộ tiền xử lý bằng cách nào đó đã tìm ra rằng có một số vấn đề, và đã không.

Điều tiếp theo tôi đã cố gắng là thế này:

#define A B 
#define B A C 
#define C x 

A 
B 

Bây giờ đến, đối với tôi, kết quả không thể giải thích:

A x 
B x 

Làm sao điều này xảy ra? Tôi không thể tìm ra cách hợp lý nào về chuyện này xảy ra như thế nào. Lệnh đầu tiên (#define A B) không thể được thực hiện, bởi vì sau đó A sẽ được thay thế bằng B và kết quả cuối cùng sẽ giống nhau cho cả hai. Nhưng nếu không, thì không có cách nào "A x" có thể xảy ra!

Câu hỏi của tôi: Tôi đang thiếu gì? Rõ ràng là tôi không biết chính xác cách thức xử lý tiền xử lý. Bạn có biết bất kỳ nguồn nào về nó không?

+0

Và đây là lý do tại sao #defines cần tránh ... – Goz

+0

Vâng, đây là lý do KHÁC .. Không phải là tôi có nghĩa là không sử dụng chúng chút nào. Đối với một số nhiệm vụ, chúng rất hữu ích (và cách để đi vào giờ sáng). – George

Trả lời

13

Self-Referential Macros giải thích. Mở rộng được áp dụng một cách sâu sắc nhưng dừng lại khi một tham chiếu macro chính nó.

+0

Liên kết đẹp và hữu ích, cảm ơn! – George

5
#define A B 
#define B A C 
#define C x 

A -> B -> A C -> A x 
B -> A C -> B x 

Expansion là mã thông báo là thẻ "uể oải"

3

Vâng, ok, có lẽ không phải là điều bất cứ ai sẽ mong đợi, nhưng nó là giải thích được. Tôi đoán rằng bộ tiền xử lý bằng cách nào đó đã tìm ra được rằng có một số vấn đề và không hoạt động.

Không. Nếu bộ tiền xử lý thực hiện mở rộng, nó chỉ mở rộng một biểu tượng một lần. Vì vậy, trong ví dụ đầu tiên của bạn cho A: A được mở rộng đến B, B mở rộng đến A và ở đây việc mở rộng dừng lại. Trong dòng thứ hai, B được mở rộng đến một A mở rộng tới B, khi mở rộng dừng lại, bởi vì chúng ta đã mở rộng B rồi.

Nếu bạn áp dụng logic cho ví dụ thứ hai của mình, thì kết quả sẽ trở nên rõ ràng ngay lập tức.

5

Mỗi chuỗi thay thế có thể truy cập bất kỳ định nghĩa macro nào nhiều nhất một lần. Trong số những thứ khác, điều này có nghĩa là bạn không thể có macro đệ quy.

Các thay ví dụ thứ hai của bạn sẽ trông như thế này:

A --[evaluate A]--> B --[evaluate B]--> A C --[evaluate C]--> A x 
B --[evaluate B]--> A C --[evaluate A,C]--> B x 

Trong bước cuối cùng của dòng đầu tiên, A là không được đánh giá bởi vì nó đã được gọi trước đó. Tương tự, trong dòng thứ hai, đánh giá dừng lại tại B vì nó đã được truy cập trong bước đầu tiên.

Phần có liên quan của tiêu chuẩn C99 sẽ là 6.10.3.4 Quét lại và thay thế thêm.

+0

Cảm ơn bạn đã giải thích! Tôi đã suy nghĩ trong bối cảnh ngữ pháp và ngôn ngữ và tôi hoàn toàn bỏ qua lời giải thích rõ ràng đó. – George