2010-07-09 62 views
6

Tôi muốn xác định một chức năng như MACRO. ví dụ:Định nghĩa macro giống chức năng trong C

#define foo(x)\ 
#if x>32\ 
x\ 
#else\ 
(2*x)\ 
#endif 

có nghĩa là,

if x>32, then foo(x) present x 
else, foo(x) present (2*x) 

nhưng GCC của tôi phàn nàn về:

int a = foo(31); 

Tôi nghĩ rằng C Preprocessor nên xử lý việc này một cách chính xác. kể từ lúc biên dịch, nó biết x=33. nó có thể thay thế foo(33) với (2*33)

+1

Tôi có thể hỏi tại sao bạn cần macro cho điều này? Một chức năng sẽ sạch hơn và (loại) an toàn hơn. –

+0

Nếu bạn biết đủ nhỏ để đặt câu hỏi này, bạn nên quên rằng '#define foo (x)' xây dựng tồn tại vì nó sẽ chỉ giúp bạn viết mã rằng nếu nó hoạt động như vậy một cách tình cờ. – msw

+1

Tôi muốn bộ tiền xử lý C thực hiện đánh giá instaed kiểm soát dòng thời gian chạy. Bằng cách này tiết kiệm thời gian tại thời gian chạy – richard

Trả lời

2

xem xét:

int x = rand() 
int y = foo(x); 

x không được biết đến tại thời gian biên dịch.

+0

Có thể trình biên dịch tìm ra nếu một biểu thức là không đổi (GCC có '__builtin_constant_p', ví dụ), tuy nhiên bộ tiền xử lý ISO C không thể. – YoYoYonnY

11

Bạn có thể như sau

#define foo(x) ((x) > 32 ? (x) : (2 * (x))) 

Nhưng đó đánh giá x nhiều lần. Thay vào đó có thể tạo một hàm tĩnh, đó là sạch

static int foo(int x) { 
    if(x > 32) 
    return x; 
    return 2 * x; 
} 

Sau đó, bạn cũng có thể vượt qua mọi thứ để foo rằng có tác dụng phụ, và có tác dụng phụ xảy ra một lần duy nhất.

Những gì bạn đã viết đang sử dụng các chỉ thị tiền xử lý #if, #else#endif, nhưng bạn cần sử dụng cấu trúc ngôn ngữ nếu bạn chuyển biến cho macro và muốn đánh giá các giá trị của chúng. Sử dụng các câu lệnh ifelse như trong các cấu trúc ngôn ngữ thực tế không hoạt động, bởi vì các câu lệnh dòng điều khiển không đánh giá các giá trị. Nói cách khác, một câu lệnh if là dòng điều khiển chỉ đạo ("nếu A, sau đó thực thi B, thì thực thi C"), không đánh giá bất kỳ giá trị nào.

+0

Chắc chắn x được đánh giá hai lần trong cả hai trường hợp? –

+1

@Neil đối số (không phải tham số) chỉ được đánh giá một lần trong trường hợp hàm. Thử gọi 'int i = 0; foo (i ++); 'Đối với trường hợp hàm, tôi sẽ là' 1' sau đó. Nhưng đối với trường hợp macro, nó sẽ là '2'. –

+0

Tôi muốn bộ tiền xử lý C thực hiện đánh giá instaed kiểm soát dòng thời gian chạy. cách này tiết kiệm thời gian trong thời gian chạy. BTW tại sao bạn nói "#define foo (x) ((x)> 32? (X): (2 * (x))) đánh giá x nhiều lần"? – richard

2
int a = foo(31); 

Mở rộng ra

int a = if 31>32 
31 
else 
(2*31) 
endif; 

Đó là cách C macro làm việc, thông qua, thay thế đơn giản câm. Nếu bạn mong đợi gcc làm bất cứ điều gì phức tạp hơn hoặc thông minh hơn với họ, thì kỳ vọng của bạn là sai lầm.

Do đó, thật dễ dàng để biết tại sao mã của bạn không hoạt động. Một thay thế đó sẽ là đủ cho ví dụ này sẽ là:

#define foo(x) (x > 32 ? x : 2*x) 

Mặt khác, tôi sẽ đặt câu hỏi liệu các macro thực sự là công cụ thích hợp cho một điều như vậy để bắt đầu với. Chỉ cần đặt nó vào chức năng và trình biên dịch sẽ inline mã nếu nó nghĩ rằng nó sẽ tăng tốc độ nó lên.

+1

Dấu x trong macro trong câu trả lời của tôi sẽ được bao bọc trong dấu ngoặc đơn như trong macro của Johannes. Nếu không, nó sẽ thất bại cho các biểu thức phức tạp.Đây là một lý do khác để tránh các macro – lỗi đơn giản, vô hại có thể gây ra các lỗi rất lạ trên đường. –

1

Vấn đề không phải là về lý thuyết: với lý do nào đó, muốn có macro mở rộng khác nhau theo giá trị của tham số được truyền cho nó và tham số này là hằng số, được biết đến macro preprocessor, không có lý do tại sao nó không thể làm việc ... cho một bộ xử lý macro chung ... Nhưng cpp unluckly không cho phép sự hiện diện của các bộ xử lý macro "lệnh" khác vào một định nghĩa macro ...

Vì vậy, bạn

#define foo(x) \ 
#if x>32 \ 
    x  \ 
#else \ 
    2*x \ 
#endif 

không mở rộng đến

#if X>32 
    X 
#else 
    2*X 
#endif 

trong đó X là tham số được biết đến (để thay đổi X để ví dụ 31), đòi hỏi một đường chuyền bằng vi xử lý.

Ngoài ra, các dòng mới bị bỏ qua, trong khi chúng quan trọng cho việc sử dụng như vậy; nếu không, sau có thể được coi như một thủ thuật (cần tuy nhiên một tiền xử lý vượt qua)

#define foo(x,y) \ 
y if x>32 \ 
    x \ 
y else \ 
    2*x \ 
y endif 

rằng với foo(20,#) sản xuất

# if 20>32 20 # else 2*20 # endif 

mà sẽ làm việc, nếu nó sẽ là

# if 20>32 
    20 
# else 
    2*20 
# endif 

... nhưng không phải (và như đã nói, đầu ra của bộ tiền xử lý phải được nạp lại cho bộ tiền xử lý một lần nữa ...)

Vì vậy, câu trả lời của tôi là nếu bạn cần những thứ này, bạn không thể sử dụng bộ tiền xử lý C; bạn nên sử dụng bộ tiền xử lý C không phổ biến (không chuẩn?), hoặc chỉ là một bộ xử lý macro khác, và nếu bạn cần những thứ mà "cpp" phải "tích hợp" với C, thì bạn không thể sử dụng cái chung (như M4) thật dễ dàng ...

+0

Vấn đề không phải là về lý thuyết: với lý do nào đó, bạn muốn có macro mở rộng khác nhau theo giá trị của tham số được truyền cho nó, và tham số này là hằng số, được biết đến với bộ tiền xử lý macro. Vâng, bạn có quan điểm của tôi. nhưng giải pháp rất phức tạp. Còn cách nào khác không? – richard

+0

như đã nói, không thay đổi bộ xử lý macro (trước) ... hiện tại tôi không biết bộ xử lý macro tương tự như cpp với tính năng bạn cần – ShinTakezou

6
#define \ 
    foo(x) \ 
    ({ \ 
     int xx = (x); \ 
     int result = (xx > 32) ? xx : (2*xx); \ 
     result; \ 
    }) 
+0

Bạn đã thử sử dụng tính năng này chưa? –

+0

@Michael: chắc chắn! Trên Ubuntu 10.04 với gcc. Các macro hạt nhân Linux thường làm như vậy. Và tôi đã sử dụng nó rộng rãi trong một dự án Linux C++ của tôi. Điều gì có vẻ lạ đối với bạn trong đoạn mã của tôi? –

+0

@Michael: thử 'grep -C2 -rn '})'. | grep -v Tài liệu | less' trên một cây nguồn Linux và bạn sẽ tìm thấy cùng một kỹ thuật được sử dụng ở rất nhiều nơi :-) –

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