2011-06-28 27 views
16

Dòng này có ý nghĩa gì? Đặc biệt, ## có nghĩa là gì?## trong #define có nghĩa là gì?

 
#define ANALYZE(variable, flag)  ((Something.##variable) & (flag)) 

Edit:

Một chút bối rối vẫn. Kết quả sẽ là gì nếu không có ##?

+0

cũng thấy: http://stackoverflow.com/questions/1597007/creating-c-macro-with-and-line-token-concatenation-with-positioning-macro – sharkin

Trả lời

8

A little bit confused still. What will the result be without ##?

Thông thường, bạn sẽ không nhận thấy bất kỳ sự khác biệt.Nhưng có sự khác biệt. Giả sử rằng Something là loại:

struct X { int x; }; 
X Something; 

Và nhìn vào:

int X::*p = &X::x; 
ANALYZE(x, flag) 
ANALYZE(*p, flag) 

Nếu không có dấu hiệu điều hành nối ##, nó mở rộng tới:

#define ANALYZE(variable, flag)  ((Something.variable) & (flag)) 

((Something. x) & (flag)) 
((Something. *p) & (flag)) // . and * are not concatenated to one token. syntax error! 

Với nối thẻ nó mở rộng tới:

#define ANALYZE(variable, flag)  ((Something.##variable) & (flag)) 

((Something.x) & (flag)) 
((Something.*p) & (flag)) // .* is a newly generated token, now it works! 

Điều quan trọng cần nhớ là bộ tiền xử lý hoạt động trên mã thông báo tiền xử lý, không phải trên văn bản. Vì vậy, nếu bạn muốn nối hai thẻ, bạn phải nói rõ ràng.

10

## được gọi là nối mã thông báo, được sử dụng để nối hai mã thông báo trong lời gọi macro.

Xem này:

+3

Trong thực tế, nó được gọi là nối thẻ. Tôi không nghĩ rằng tài liệu cho trình biên dịch AIX C/C++ của IBM là tài liệu tham khảo tốt nhất! –

+0

@David: Đã thêm câu trả lời này vào câu trả lời của tôi. Cảm ơn :-) – Nawaz

+0

@ David: Tôi không nói trình biên dịch AIX C/C++ của IBM là tham chiếu tốt nhất. Tham khảo tốt nhất là không có gì khác hơn so với bản thân tiêu chuẩn. Tuy nhiên, chúng tôi vẫn cung cấp liên kết tới các trang web khác, bao gồm các chủ đề tại stackoverflow. – Nawaz

3

Theo Wikipedia

Token concatenation, also called token pasting, is one of the most subtle — and easy to abuse — features of the C macro preprocessor. Two arguments can be 'glued' together using ## preprocessor operator; this allows two tokens to be concatenated in the preprocessed code. This can be used to construct elaborate macros which act like a crude version of C++ templates.

Kiểm tra Token Concatenation

8

Một phần rất quan trọng là nối thẻ này sau một số quy tắc rất đặc biệt :

ví dụ: Tài liệu IBM:

  • Kết hợp diễn ra trước khi bất kỳ macro nào trong đối số được mở rộng.
  • Nếu kết quả của một nối là một tên macro hợp lệ, nó có sẵn cho thay thế tiếp tục ngay cả khi nó xuất hiện trong một bối cảnh trong đó nó thường không có sẵn.
  • Nếu nhiều hơn một ## nhà điều hành và/hoặC# điều hành xuất hiện trong thay thế danh sách các định nghĩa vĩ mô, thứ tự đánh giá của các nhà khai thác không được định nghĩa.

Ví dụ cũng rất tự giải thích

#define ArgArg(x, y)   x##y 
#define ArgText(x)   x##TEXT 
#define TextArg(x)   TEXT##x 
#define TextText    TEXT##text 
#define Jitter    1 
#define bug     2 
#define Jitterbug    3 

Với đầu ra:

ArgArg(lady, bug) "ladybug" 
ArgText(con) "conTEXT" 
TextArg(book) "TEXTbook" 
TextText "TEXTtext" 
ArgArg(Jitter, bug)  3 

Nguồn là tài liệu của IBM. Có thể thay đổi với các trình biên dịch khác.

Để dòng của bạn:

Nó concatenates thuộc tính biến đến "Một cái gì đó." và đặt một biến là logic và được cung cấp như là kết quả nếu Something.variable có một bộ cờ.

Vì vậy, một ví dụ để bình luận cuối cùng của tôi và câu hỏi của bạn (compileable với g ++):

// this one fails with a compiler error 
// #define ANALYZE1(variable, flag)  ((Something.##variable) & (flag)) 
// this one will address Something.a (struct) 
#define ANALYZE2(variable, flag)  ((Something.variable) & (flag)) 
// this one will be Somethinga (global) 
#define ANALYZE3(variable, flag)  ((Something##variable) & (flag)) 
#include <iostream> 
using namespace std; 

struct something{ 
int a; 
}; 

int Somethinga = 0; 

int main() 
{ 
something Something; 
Something.a = 1; 

if (ANALYZE2(a,1)) 
    cout << "Something.a is 1" << endl; 
if (!ANALYZE3(a,1)) 
    cout << "Somethinga is 0" << endl; 
     return 1; 
}; 
+0

Kết quả sẽ là gì nếu không có '##'? –

+0

để kiểm tra của tôi dẫn đến. Gcc phàn nàn về 'a. ## b'. 'a ## b' đánh giá đúng cho toàn cầu. 'a.b' đánh giá cũng đúng với một biến bên trong cá thể struct a. – fyr

+0

Tôi đã thêm một ví dụ làm phần bổ sung. – fyr

2

cho phép xem xét một ví dụ khác:

xem xét

#define MYMACRO(x,y) x##y 

mà không ##, rõ Preprocessor không thể nhìn thấy xy như thẻ riêng biệt, có thể nó?

Trong ví dụ của bạn,

#define ANALYZE(variable, flag)  ((Something.##variable) & (flag)) 

## chỉ đơn giản là không cần thiết như bạn đang không thực hiện bất kỳ nhận dạng mới. Trong thực tế, các lỗi trình biên dịch "lỗi: dán". "Và" biến "không cung cấp mã thông báo tiền xử lý hợp lệ"

2

Đây không phải là câu trả lời cho câu hỏi của bạn, chỉ một bài đăng CW với một số mẹo giúp bạn khám phá bộ tiền xử lý bản thân bạn.

Bước tiền xử lý thực sự được thực hiện trước khi bất kỳ mã thực nào được biên dịch. Nói cách khác, khi trình biên dịch bắt đầu tạo mã của bạn, không có tuyên bố số #define hoặc bất kỳ thứ gì như thế được để lại.

Một cách hay để hiểu những gì mà bộ tiền xử lý thực hiện cho mã của bạn là nắm giữ đầu ra được xử lý trước và xem xét nó.

Đây là cách để làm điều đó cho Windows:

Tạo một tập tin đơn giản gọi là test.cpp và đặt nó trong một thư mục, nói c: \ temp. Mỏ trông giống như sau:

#define dog_suffix(variable_name) variable_name##dog 

int main() 
{ 
    int dog_suffix(my_int) = 0; 
    char dog_suffix(my_char) = 'a'; 

    return 0; 
} 

Không phải rất hữu ích, nhưng đơn giản. Mở Visual Studio lệnh nhanh chóng, điều hướng đến thư mục và chạy dòng lệnh sau:

c:\temp>cl test.cpp /P 

Vì vậy, nó là trình biên dịch của bạn chạy (cl.exe), với tập tin của bạn, và tùy chọn/P nói với trình biên dịch để lưu trữ đầu ra được xử lý trước vào một tập tin.

Bây giờ trong thư mục bên cạnh test.cpp bạn sẽ tìm thấy kiểm tra.i, mà đối với tôi trông như thế này:

#line 1 "test.cpp" 


int main() 
{ 
    int my_intdog = 0; 
    char my_chardog = 'a'; 

    return 0; 
} 

Như bạn có thể thấy, không #define trái, chỉ có mã nó mở rộng sang.