2012-10-20 44 views
9

Tôi đang cố gắng tạo macro bằng công thức sau: (a^2/(a+b))*b và tôi muốn đảm bảo rằng sẽ không có chia cho 0.Có thể sử dụng câu lệnh if trong #define không?

#define SUM_A(x, y) if(x == 0 || y == 0) { 0 } else { (((x * x)/((x) + (y))) * (y))} 

và sau đó tôi gọi là macro bên chính:

float a = 40, b = 10, result; 
result = SUM_A(a, b); 
printf("%f", result); 

Tôi đã thử sử dụng dấu ngoặc xung quanh nếu chức năng nhưng tôi cứ bị lỗi cú pháp trước khi câu lệnh if. Tôi cũng đã cố gắng sử dụng trở lại, nhưng tôi đọc một nơi nào đó mà bạn không được sử dụng để xác định.

Trả lời

14

Bạn không thể sử dụng câu lệnh if, vì #define được giải thích bằng vi xử lý, và sản lượng sẽ được

result=if(x == 0 || y == 0) { 0 } else { (((x * x)/((x) + (y))) * (y))} 

đó là cú pháp sai.

Nhưng cách khác là sử dụng toán tử bậc ba. Thay đổi xác định của bạn thành

#define SUM_A(x, y) ((x) == 0 || (y) == 0 ? 0 : ((((x) * (x))/((x) + (y))) * (y))) 

Hãy nhớ luôn đặt định nghĩa của bạn giữa dấu ngoặc đơn, để tránh lỗi cú pháp khi thay thế.

+1

Phát biểu của dấu ngoặc đơn, không nên là '(x) * (x)', '(x) == 0' và' (y) == 0'? – SirGuy

+0

thực sự. Cảm ơn bạn đã chỉ ra điều đó. – tomahh

+0

Cảm ơn bạn rất nhiều, tôi chưa bao giờ nghe nói về nhà điều hành này trước đây. – Frey1337

5

if giới thiệu một tuyên bố chứ không phải biểu thức. Sử dụng "ternary" (có điều kiện) điều hành:

#define SUM_A(x, y) (((x) == 0 || (y) == 0)? 0: ((((x) * (x))/((x) + (y))) * (y))) 

Ngoài ra, làm cho này một inline chức năng:

inline float sum_a(float x, float y) 
{ 
    if (x == 0 || y == 0) 
     return 0; 
    else 
     return ((x * x)/(x + y)) * y; 
} 

Điều này tránh được vấn đề của nhiều đánh giá x và/hoặc y và nhiều hơn nữa có thể đọc được nhưng nó sửa các loại xy. Bạn cũng có thể thả các inline và để cho trình biên dịch quyết định liệu nội tuyến chức năng này là đáng giá (inline không phải là một đảm bảo rằng nó sẽ thực hiện nội tuyến).

+0

Sự cố với chức năng là nó buộc bạn sử dụng 'float' làm kiểu dữ liệu của bạn. Có lẽ không sao, nhưng có lẽ không. – SirGuy

+0

@GuyGreer: tốt điểm, thêm rằng để trả lời. –

1

Vấn đề là tuyên bố if không phải là biểu thức và không trả về giá trị. Bên cạnh đó, không có lý do chính đáng để sử dụng macro trong trường hợp này. Trong thực tế, nó có thể gây ra vấn đề hiệu suất rất nghiêm trọng (tùy thuộc vào những gì bạn vượt qua như là đối số macro). Thay vào đó, bạn nên sử dụng hàm.

0

Có nhiều vấn đề với macro của bạn:

  • nó mở rộng đến một tuyên bố, vì vậy bạn không thể sử dụng nó như là một biểu

  • các đối số không ngoặc đúng trong việc mở rộng: cách gọi này macro với bất cứ điều gì nhưng tên biến hoặc hằng số sẽ tạo ra vấn đề.

  • đối số được đánh giá nhiều lần: nếu bạn gọi macro với đối số có tác dụng phụ, chẳng hạn như SUM_A(a(), b()) hoặc SUM_A(*p++, 2), tác dụng phụ sẽ xảy ra nhiều lần.

Để tránh tất cả những vấn đề này, sử dụng một chức năng, có thể định nghĩa là static inline để giúp trình biên dịch tối ưu hóa hơn (điều này là không bắt buộc và trình biên dịch hiện đại làm tự động này):

static inline int SUM_A(float x, float y) { 
    if (x == 0 || y == 0) 
     return 0; 
    else 
     return x * x/(x + y) * y; 
} 

Ghi chú:

  • chức năng này sử dụng số học dấu phẩy động, mà macro sẽ không nhất thiết, tùy thuộc vào loại đối số thực tế của nó.
  • phép thử không ngăn sự phân chia bằng không: SUM_A (-1, 1) vẫn thực hiện một phép thử.
  • chia cho số không nhất thiết là một vấn đề: với đối số dấu chấm động, nó tạo ra một vô cực hoặc một NaN, không phải lỗi thời gian chạy.
1

Về mặt kỹ thuật, bạn có thể sử dụng nếu câu lệnh trong #define (nhưng không theo cách bạn mong đợi). Vì #define s chỉ là văn bản thay thế, bạn phải thực sự cẩn thận về cách bạn mở rộng nó. Tôi thấy rằng làm việc này ...

#define SUM_A(x, y)        \ 
({            \ 
    double answer;        \ 
    if (x == 0 || y == 0)      \ 
     answer = 0;        \ 
    else          \ 
     answer = ((double)(x*x)/(x+y)) * y; \ 
    (answer);         \ 
}) 
// Typecasting to double necessary, since int/int rounds down to int in C 

Điều này sẽ cho bạn những kết quả mà bạn đang tìm kiếm, và không có lý do nó không thể được mở rộng để bao gồm nhiều else if s cũng (mặc dù câu trả lời là có khác chỉ ra, nó có thể dễ dàng hơn để sử dụng các nhà điều hành ternary).

1

CÓ bạn có thể có câu lệnh if trong macro. Bạn cần định dạng chính xác. Dưới đây là ví dụ:

#define MY_FUNCTION(x) if(x) { PRINT("TRUE"); } else { PRINT("FALSE"); } 
Các vấn đề liên quan