2010-06-13 32 views
7

Cảnh báo: Đây là một câu hỏi lạ.Mở rộng macro có điều kiện

Tôi có một số macro thực sự hữu ích mà tôi thích sử dụng để đơn giản hóa việc ghi nhật ký. Ví dụ: tôi có thể thực hiện Log(@"My message with arguments: %@, %@, %@", @"arg1", @"arg2", @"arg3") và điều đó sẽ được mở rộng thành lời gọi phương thức phức tạp hơn bao gồm những thứ như self, _cmd, __FILE__, __LINE__, v.v ... để tôi có thể dễ dàng theo dõi mọi thứ đang được ghi nhật ký. Điều này làm việc tuyệt vời.

Bây giờ tôi muốn mở rộng các macro của mình để không chỉ hoạt động với các phương pháp Objective-C mà còn là các hàm C chung. Vấn đề là các phần self_cmd nằm trong phần mở rộng macro. Hai tham số này không tồn tại trong các hàm C. Lý tưởng nhất, tôi muốn có thể sử dụng cùng một bộ macro trong các hàm C, nhưng tôi đang gặp sự cố. Khi tôi sử dụng (ví dụ) của tôi vĩ mô Log(), tôi nhận được cảnh báo trình biên dịch về self_cmd không khai báo (mà làm cho ý nghĩa tổng thể).

Suy nghĩ đầu tiên của tôi là phải làm một cái gì đó như sau (trong vĩ mô của tôi):

if (thisFunctionIsACFunction) { 
    DoLogging(nil, nil, format, ##__VA_ARGS__); 
} else { 
    DoLogging(self, _cmd, format, ##__VA_ARGS__); 
} 

này vẫn tạo ra cảnh báo trình biên dịch, vì toàn bộ if() tuyên bố được thay thế ở vị trí của vĩ mô, dẫn đến lỗi với các từ khóa self_cmd (mặc dù chúng sẽ không bao giờ được thực hiện trong khi thực hiện hàm).

suy nghĩ tiếp theo của tôi là để làm một cái gì đó như thế này (ở vĩ mô của tôi):

if (thisFunctionIsACFunction) { 
    #define SELF nil 
    #define CMD nil 
} else { 
    #define SELF self 
    #define CMD _cmd 
} 
DoLogging(SELF, CMD, format, ##__VA_ARGS__); 

Điều đó không làm việc, không may. Tôi nhận được "lỗi: '#' không được theo sau bởi tham số macro" trên #define đầu tiên của tôi.

Suy nghĩ khác của tôi là tạo bộ macro thứ hai, đặc biệt để sử dụng trong các hàm C. Reeks này của một mùi mã xấu, và tôi thực sự không muốn làm điều này.

Có cách nào tôi có thể sử dụng cùng một tập hợp macro từ bên trong cả hai phương thức Objective-C và C và chỉ tham chiếu self_cmd nếu macro nằm trong phương pháp C-mục tiêu?

chỉnh sửa biết thêm thông tin:

thisFunctionIsACFunction được xác định một cách khá thô sơ (và tôi chắc chắn mở để cải tiến và đề nghị). Về cơ bản, điều này là:

BOOL thisFunctionIsACFunction == (__PRETTY_FUNCTION__[0] != '-' && __PRETTY_FUNCTION__[0] != '+'); 

Nó dựa vào hành vi của trình biên dịch để thêm một '-' hoặc '+' ví dụ và phương thức lớp vào đối tượng Objective-C. Mọi thứ khác phải là hàm C (vì hàm C không thể có tên bắt đầu bằng '-' hoặc '+').

Tôi hiểu rằng kiểm tra này về mặt kỹ thuật là kiểm tra thời gian chạy, vì __PRETTY_FUNCTION__ được thay thế bằng char* và đây có thể là rào cản chính cho yêu cầu trợ giúp của tôi.

+0

Làm thế nào để bạn đưa ra với 'thisFunctionIsACFunction'? – Artelius

+0

@Artelius câu hỏi được chỉnh sửa với nhiều thông tin hơn –

Trả lời

7

Bộ xử lý trước thực hiện tất cả công việc của nó trước khi mã thực tế được phân tích cú pháp. Bộ tiền xử lý không thể biết một hàm là C hay obj-C vì nó chạy trước khi mã được phân tích cú pháp.

Đối với lý do tương tự,

if (thisFunctionIsACFunction) { 
    #define SELF nil 
    #define CMD nil 
} else { 
    #define SELF self 
    #define CMD _cmd 
} 
DoLogging(SELF, CMD, format, ##__VA_ARGS__); 

không thể làm việc - cáC# định nghĩa được xử lý trước khi giai đoạn biên dịch.

Vì vậy, bản thân mã phải chứa kiểm tra "thời gian chạy" (mặc dù trình biên dịch có thể tối ưu hóa việc này).

tôi sẽ đề nghị xác định cái gì đó như

void *self = nil; //not sure about the types that 
SEL _cmd = nil; //would be valid for obj-c 

ở phạm vi toàn cầu; các hàm C sẽ "nhìn thấy" các định nghĩa này trong khi các phương thức Objective-C hy vọng sẽ ẩn chúng với các định nghĩa riêng của chúng.

+0

+1 Ha! Bạn là một thiên tài! Tôi sẽ không bao giờ nghĩ đến việc định nghĩa 'self' và' _cmd' ở cấp độ toàn cầu! Cảm ơn! (Và nó hoạt động hoàn hảo; tôi chỉ thử nó.) –

0

Bạn có thể sử dụng một số loại có điều kiện vĩ mô:

#ifndef OBJECTIVE_C 
    #define self 0 
    #define _cmd "" 
#endif 

Tôi không khá chắc chắn những gì bạn cần xác định self_cmd đến, đó là những chỉ đoán.

Tôi không chắc liệu có macro được xác định trước mà bạn có thể kiểm tra xem bạn có đang biên dịch trong Mục tiêu C hay không, do đó bạn có thể cần xác định OBJECTIVE_C theo cách thủ công như một phần của bản dựng.

+0

Ý tưởng hay. Vấn đề duy nhất là Objective-C là một bộ siêu C nghiêm ngặt, có nghĩa là ObjC và C có thể cùng tồn tại một cách hòa bình song song. Điều này có nghĩa rằng hầu hết các hàm C của tôi sẽ có '__OBJC__' # define'd. –

1

Bạn có thể sử dụng

if defined "abc" <statement1> 
else if defined "def" <statement2> 
Các vấn đề liên quan