2009-07-15 37 views
17

Tôi đang viết một loạt các macro tiền xử lý có liên quan, một trong số đó tạo ra các nhãn mà macro kia sẽ chuyển đến. Tôi sử dụng chúng trong thời trang này:Làm cách nào để tạo các giá trị duy nhất trong bộ tiền xử lý C?

MAKE_FUNNY_JUMPING_LOOP(
    MAKE_LABEL(); 
    MAKE_LABEL(); 
) 

Tôi cần một số cách để tạo ra nhãn duy nhất, một cho mỗi MAKE_LABEL cuộc gọi nội, với tiền xử lý. Tôi đã thử sử dụng __LINE__, nhưng vì tôi gọi MAKE_LABEL bên trong một macro khác, tất cả đều có cùng một dòng và các nhãn va chạm.

Những gì tôi muốn này để mở rộng đến là một cái gì đó như:

MAKE_FUNNY_JUMPING_LOOP(
    my_cool_label_1: // from first inner macro 
    ... 
    my_cool_label_2: // from second inner macro 
    ... 
) 

Có cách nào để tạo ra băm hoặc số nguyên auto-incrementing với tiền xử lý?

+0

trình biên dịch gì bạn đang sử dụng? –

+0

Tôi đang sử dụng ICC (nguyên mẫu STM 3.0; dựa trên v11, tôi nghĩ). –

+0

Đối với C++: http://stackoverflow.com/questions/9949532/generate-unique-numbers-at-compile-time?lq=1 –

Trả lời

15

Như những người khác chú ý, __COUNTER__ là một cách dễ dàng nhưng không chuẩn để làm điều này.

Nếu bạn cần thêm tính di động, hoặc cho các thủ thuật tiền xử lý mát khác, Boost Preprocessor library (hoạt động cho C cũng như C++) sẽ hoạt động. Ví dụ: tệp tiêu đề sau sẽ xuất ra một nhãn duy nhất ở bất kỳ nơi nào được bao gồm.

#include <boost/preprocessor/arithmetic/inc.hpp> 
#include <boost/preprocessor/slot/slot.hpp> 

#if !defined(UNIQUE_LABEL) 
#define UNIQUE_LABEL 
#define BOOST_PP_VALUE 1 
#include BOOST_PP_ASSIGN_SLOT(1) 
#undef BOOST_PP_VALUE 
#else 
#define BOOST_PP_VALUE BOOST_PP_INC(BOOST_PP_SLOT(1)) 
#include BOOST_PP_ASSIGN_SLOT(1) 
#undef BOOST_PP_VALUE 
#endif 


BOOST_PP_CAT(my_cool_label_, BOOST_PP_SLOT(1)): 

mẫu:

int main(int argc, char *argv[]) { 
    #include "unique_label.h" 
    printf("%x\n", 1234); 
    #include "unique_label.h" 
    printf("%x\n", 1234); 
    #include "unique_label.h" 
    return 0; 
} 

preprocesses để

int main(int argc, char *argv[]) { 
    my_cool_label_1: 
    printf("%x\n", 1234); 
    my_cool_label_2: 
    printf("%x\n", 1234); 
    my_cool_label_3: 
    return 0; 
} 
+0

Đây là câu trả lời hay! Cảm ơn con trỏ; Tôi thừa nhận tôi tìm thấy tài liệu Boost.Preprocessor một chút dày đặc. –

+0

Tôi thấy nó quá dày đặc. Tôi thường phải fiddle một chút với cú pháp để tìm một cái gì đó mà làm việc, nhưng nó mát mẻ khi nó. –

+5

Boost.Preprocessor là phép thuật vô lý. –

7

Tôi không thể nghĩ ra một cách để tự động tạo ra chúng, nhưng bạn có thể vượt qua một tham số để MAKE_LABEL:

#define MAKE_LABEL(n) my_cool_label_##n: 

Sau đó ...

MAKE_FUNNY_JUMPING_LOOP(
    MAKE_LABEL(0); 
    MAKE_LABEL(1); 
) 
+3

Tất nhiên, nó cũng có thể bao gồm macro __LINE__ như một phần của định nghĩa MAKE_LABEL() các macro khác của bạn vẫn có thể sử dụng nó (miễn là bạn không sử dụng các macro đó nhiều hơn một lần trong một số macro khác ...) –

+0

Cuộc gọi tốt. Tôi thực sự đã làm điều này cho macro 'MAKE_FUNNY_JUMPING_LOOP', vì có khá ít trong số đó và chúng dễ mô tả. Tôi đoán nếu đó chỉ là một, tôi có thể đối phó với điều đó. Tuy nhiên, việc phát tán phương pháp thủ công cho mọi macro như thế này là quá nhiều đối với tôi. –

-2

Nó dường như không thể thực hiện với bộ tiền xử lý chuẩn, mặc dù bạn có thể giả mạo nó bằng cách đặt các tham số bên trong MAKE_LABEL hoặc MAKE_FUNNY_JUMPING_LOOP và sử dụng dán mã thông báo để tạo nhãn.

Không có gì ngăn cản bạn tạo tập lệnh tiền xử lý của riêng bạn mà làm tăng tự động cho bạn. Tuy nhiên, nó sẽ không phải là một tệp C/C++ chuẩn trong trường hợp đó.

Một danh sách các lệnh có sẵn: http://www.cppreference.com/wiki/preprocessor/start

17

Nếu bạn đang sử dụng GCC hoặc MSVC, có __COUNTER__.

Ngoài ra, bạn có thể làm một cái gì đó nôn mửa-xứng đáng, như:

#ifndef USED_1 
#define USED_1 
1 
#else 
#ifndef USED_2 
#define USED_2 
2 
/* many many more */ 
#endif 
#endif 
+1

Tìm tốt. Học điều mới mỗi ngày. –

+0

Anh ta có cần phải quan tâm rằng nó không được sử dụng trong bất kỳ đơn vị biên dịch nào khác không? Nếu không, nó có thể bất ngờ bỏ qua số. –

+4

@Jesse: Mỗi đơn vị biên dịch được chạy tiền xử lý riêng, vì vậy __COUNTER__ phải luôn bắt đầu ở 0. Tuy nhiên, có thể người khác có thể sử dụng __COUNTER__ trong cùng một đơn vị biên dịch, dẫn đến các lỗ trong chuỗi. – derobert

0

Bạn có thể làm điều này:

#define MAKE_LABEL() \ 
do {     \ 
my_cool_label:  \ 
/* some stuff */; \ 
goto my_cool_label; \ 
/* other stuff */; \ 
} while (0) 

Điều này sẽ giúp các phạm vi của nhãn địa phương, cho phép bất kỳ số lượng chúng bên trong macro chính.

Nếu bạn muốn nhãn được truy cập toàn cầu hơn, không rõ cách macro của bạn "MAKE_FUNNY_JUMPING_LOOP" tham chiếu đến các nhãn này. Bạn có thể giải thích?

15

tôi sử dụng này:

#define MERGE_(a,b) a##b 
#define LABEL_(a) MERGE_(unique_name_, a) 
#define UNIQUE_NAME LABEL_(__LINE__) 

int main() 
{ 
    int UNIQUE_NAME = 1; 
    return 0; 
} 

... và nhận được như sau:

int main() 
{ 
    int unique_name_8 = 1; 
    return 0; 
} 
+1

Và làm thế nào để bạn thực sự sử dụng biến? Bạn không thể. – this

+2

.... bạn sẽ cần phải thêm một tên không duy nhất trong macro để truy cập vào tên duy nhất, đặt bạn trở lại hình vuông ... có vẻ như chúng ta quá điên rồ với bộ tiền xử lý và bắt đầu suy nghĩ về cách nó có thể làm tất cả công việc cho chúng tôi, không có vấn đề làm thế nào không thực tế .. chưa kể đến thời gian. (tôi, tôi gõ một cái gì đó độc đáo và di chuyển trên .. heh) nhưng tôi nghĩ rằng giải pháp COUNTER cho MSVC/GCC là tốt, và nếu bạn đang sử dụng cái gì khác thì sử dụng công cụ tăng ... đầu tiên hai câu trả lời là tốt – osirisgothra

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