Đầu ra của mã C này là 49 nhưng ai đó có thể giải thích cho tôi làm thế nào? [bản sao]
#include <stdio.h>
#define CUBE(x) (x * x * x)
int main() {
printf("%d", CUBE(4+5));
return 0;
}
Trả lời
Macro sẽ chuyển mã thành:
printf("%d", (4+5 * 4+5 * 4+5));
hiệu quả là:
printf("%d", 4 + (5*4) + (5*4) + 5); // 29
Nếu bạn muốn lập phương 9
để có được 729
, bạn nên viết CUBE((4+5))
.
Đây là cách macro được mở rộng trong quá trình biên dịch:
printf("%d", (4+5 * 4+5 * 4+5));
Vì *
có mức độ ưu tiên cao hơn +
, biểu thức này được đánh giá là (4 + (5 * 4) + (5 * 4) + 5)
, tạo ra 49
thay vì mong đợi 729
.
Để tránh các vấn đề về ưu tiên toán tử như vậy, tất cả các đối số macro phải được đặt trong ngoặc đơn trong định nghĩa macro cũng như bản thân biểu thức:
#define CUBE(x) ((x) * (x) * (x))
Tuy nhiên, lưu ý rằng việc mở rộng này CUBE
đánh giá x
nhiều lần, đây là một vấn đề nếu đối số macro có tác dụng phụ, chẳng hạn như CUBE(i++)
.
Để tránh tất cả những vấn đề này, hãy sử dụng một hàm và để trình biên dịch tối ưu hóa nó:
int cube(int x) {
return x * x * x;
}
Bạn có thể thêm static inline
vào trước định nghĩa hàm này, nhưng các trình tối ưu hóa hiện đại vẫn sẽ nội dòng hàm mà không có định nghĩa này.
Bộ tiền xử lý C theo nghĩa đen sẽ thay thế tất cả các trường hợp của x cho 4 + 5, dẫn đến đoạn mã sau:
i = 4+5*4+5*4+5;
(nhân trước, sau đó cộng)
bạn cần cung cấp đầu vào như CUBE((4+5))
nếu bạn muốn thêm các số và sau đó gửi đến CUBE
. Nguyên nhân CUBE(4+5)
về cơ bản được mở rộng thành 4+5*4+5*4+5
vì nó đặt toàn bộ 4+5
vào vị trí của x
. Vì vậy, 4+5*4+5*4+5
= 4+20+20+5
khi phép nhân đến trước và sau đó cộng chúng sẽ cho 49
.
Xác định macro giống như #define CUBE(x) ((x)*(x)*(x))
nó thực sự đầu tiên tiến hành (4+5)
hoạt động cho mọi (x)
và sau đó thực hiện *
hoạt động.
Một cách khác là chỉ sử dụng CUBE((4+5))
trong khi gọi macro, về cơ bản, trước tiên nó thêm hai số và (4+5)
= 9
và sau đó thực hiện CUBE(9)
, như:
#include<stdio.h>
#define CUBE(x) (x * x * x)
int main( )
{
printf("%d", CUBE((4+5)));
return 0;
}
Đọc Modern C , sau đó là bản dự thảo tiêu chuẩn C n1570 và tài liệu về GCC , GDB và CPP . Xem thêm trang web tham khảo C này .
Lấy cảm hứng từ các dự án mã nguồn mở hiện có, ví dụ như trên github hoặc phần mềm GNU .
Với trình biên dịch GCC gần đây , hãy gọi nó là gcc -Wall -Wextra -g
. Cũng sử dụng các -C -E
tùy chọn để lấy biểu mẫu được xử lý trước.
Bạn cũng có thể quan tâm bởi những tuyên bố-expr mở rộng của GCC.
Bạn CUBE(4+5)
là vĩ mô mở rộng để 4+5*4+5*4+5
có được tính như 4+(5*4)+(5*4)+5
theo thứ tự ưu tiên của các nhà khai thác C .
Cân nhắc mã hóa một static inline
chức năng như
static inline int cube(int x) { return x*x*x; }
hoặc nếu bạn cần một macro, ít nhất
#define CUBE(X) ((X)*(X)*(X))
điều này sẽ không hoạt động tốt CUBE(i++)
(trong khi với inline
hàm, cube(i++)
thực hiện những gì bạn muốn nó làm: tăng i
một lần!).
BTW, bạn có thể sử dụng GPP , hoặc GNU m4 , (hoặc bộ tạo của riêng bạn, hoặc GNU bison ) để tạo một số mã C. Theo nguyên tắc chung, hãy nghĩ với AST : khi bạn tạo mã C, hãy tạo ra rất nhiều dấu ngoặc đơn vô dụng, như trong Chicken Scheme , SWIG , hoặc trong CAIA hoặc trong manydl.c của tôi
Bạn cũng có thể sử dụng trình phân tích tĩnh Clang trên mã của mình (và có thể là Frama-C ).
Bạn có thể quan tâm đến việc đọc một số hướng dẫn mã hóa như MISRA C hoặc GNU .