2015-06-12 13 views
7

Tôi đang đọc về mở rộng macro CPP và muốn hiểu mở rộng khi chuỗi mã thông báo (tùy chọn) không được cung cấp. Tôi đã tìm thấy gcc v4.8.4 thực hiện điều này:mở rộng cpp của macro không có mã thông báo

$ cat zz.c 
#define B 
(B) 
|B| 
$ gcc -E zz.c 
# 1 "zz.c" 
# 1 "<built-in>" 
# 1 "<command-line>" 
# 1 "zz.c" 

() 
| | 

Bất cứ ai có thể giải thích lý do mở rộng không gian bằng một trường hợp và một không?

+1

Có lẽ vì '|' và '|| ' là các toán tử khác nhau. Tôi hy vọng ai đó viết một câu trả lời với các quy tắc chính xác cpp sử dụng. – hyde

+0

Thật buồn cười khi thấy ai đó viết 'x | giá trị | SOME_FLAG' và hóa ra là 'x || SOME_FLAG', có lẽ đây là cách để nó không biên dịch. –

+0

Nhưng điều đó có nghĩa là '|| 'được coi là trường hợp đặc biệt. Điều này có thể tránh được bằng cách * luôn luôn * chèn khoảng trống, mà sẽ không được chống lại các quy tắc C (ngoại trừ các macro concatenations). – usr2564301

Trả lời

7

Bộ tiền xử lý C hoạt động trên "mã thông báo" và bất cứ khi nào có khả năng thay đổi ý nghĩa hoặc sự mơ hồ, nó luôn thêm khoảng trống để giữ nguyên nghĩa.

Hãy xem xét ví dụ của bạn,

(B) 

không có sự mơ hồ hoặc ý nghĩa thay đổi cho dù có một khoảng trống giữa () thêm hay không không phụ thuộc vào giá trị vĩ mô của B.

Nhưng nó không phải là trường hợp với

|B| 

Tùy thuộc vào vĩ mô B, này ở trên có thể thể là || hoặc |something|. Vì vậy, preprocessor buộc phải thêm một khoảng trống để giữ nguyên các quy tắc từ vựng của C.

Hành vi tương tự có thể được nhìn thấy với bất kỳ mã thông báo nào khác có thể thay đổi ý nghĩa.Ví dụ,

#define B + 
B+ 

sẽ tạo ra

+ + 

như trái ngược với

++ 

vì lý do nói.

Tuy nhiên, đây chỉ là bộ tiền xử lý tuân thủ các quy tắc từ vựng C. GCC có và hỗ trợ một bộ tiền xử lý cũ được gọi là bộ xử lý truyền thống sẽ không thêm bất kỳ khoảng trắng thừa nào. Ví dụ, nếu bạn gọi Preprocessor trong chế độ truyền thống:

gcc -E -traditional-cpp file.c 

sau đó

#define B 

(B) 
|B| 

sản (không có khoảng trắng)

() 
|| 
1

chỉnh sửa: xem câu trả lời của hvd về việc thực hiện tiền xử lý của gcc

Điều này có thể phân biệt giữa bitwise và toán tử OR logic.

mẫu này:

if (x | 4) printf("true\n"); // Bitwise OR, may or may not be true 

là khác nhau từ:

if (x || 4) printf("true\n"); // Always true 

Vì họ là những nhà khai thác khác nhau với các chức năng khác nhau, nó là cần thiết cho việc tiền xử lý để thêm khoảng trắng để tránh việc thay đổi ý nghĩa dự định tuyên bố.

+2

Nó không trả lời câu hỏi: tại sao nó được thực hiện? nó có thể đã không được thực hiện ở nơi đầu tiên. –

4

Đầu ra của gcc -E cố tình không khớp với các quy tắc chính xác được chỉ định bởi tiêu chuẩn C. Các tiêu chuẩn C không mô tả bất kỳ cách cụ thể kết quả tiền xử lý nên được nhìn thấy, và thậm chí không yêu cầu một cách tồn tại.

Lần duy nhất một số loại đầu ra tiền xử lý được yêu cầu hiển thị là khi toán tử # được sử dụng. Và nếu bạn sử dụng điều này, bạn có thể thấy rằng không có bất kỳ không gian nào. câu trả lời

flaming.toaster của toàn đúng khi chỉ ra rằng lý do gcc -E đầu ra chèn một không gian là để ngăn chặn hai liên tiếp | s từ đang được phân tích như một || thẻ duy nhất. Chương trình sau đây được yêu cầu đưa ra chẩn đoán cho lỗi cú pháp:

#define EMPTY 
int main() { return 0 |EMPTY| 0; } 

và không gian ở đó để đảm bảo trình biên dịch vẫn có đủ thông tin để thực sự tạo lỗi.

+0

Vì vậy, các tệp được quét cho các toán tử có macro ở giữa sẽ dẫn đến toán tử * đơn * khi trống? (Danh sách nhanh: '++', '--',' -> ', và toán tử boolean. Còn nữa?) – usr2564301

+0

@Jongware Hãy xem xét cả hai số nhận dạng liên tiếp:' #define F (X) X', và sau đó 'F (int) F (chính)() {}'. Trên thực tế, cách tiếp cận của GCC là hai loại mã thông báo liên tiếp có một khoảng trống được chèn vào giữa chúng nếu một số mã thông báo sẽ bị hiểu sai nếu nằm liền kề, ngay cả khi nó không phải là vấn đề đối với các mã cụ thể được đề cập, vì vậy bạn có thể thấy thêm không gian trong một vài trường hợp góc mà không cần thiết, ví dụ giữa '1' và' + ', vì' + '* có thể * xuất hiện trong một số trang (sau một' E'). – hvd

+0

Có lý do chính đáng nào để không chỉ * luôn * chèn không gian ngay trước và sau macro mở rộng không? Điều đó dường như với tôi là giải pháp đơn giản nhất ... – usr2564301

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