2015-09-04 20 views
89

Trên khắp cơ sở mã C của chúng tôi, tôi thấy tất cả các vĩ mô được xác định theo cách sau:Tại sao chỉ xác định macro nếu macro chưa được xác định?

#ifndef BEEPTRIM_PITCH_RATE_DEGPS 
#define BEEPTRIM_PITCH_RATE_DEGPS     0.2f 
#endif 

#ifndef BEEPTRIM_ROLL_RATE_DEGPS 
#define BEEPTRIM_ROLL_RATE_DEGPS     0.2f 
#endif 

#ifndef FORCETRIMRELEASE_HOLD_TIME_MS 
#define FORCETRIMRELEASE_HOLD_TIME_MS    1000.0f 
#endif 

#ifndef TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS 
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS  50.0f 
#endif 

lý do làm những xác định kiểm tra thay vì chỉ định macro là gì?

#define BEEPTRIM_PITCH_RATE_DEGPS     0.2f 
#define BEEPTRIM_ROLL_RATE_DEGPS     0.2f 
#define FORCETRIMRELEASE_HOLD_TIME_MS    1000.0f 
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS  50.0f 

Tôi không thể tìm thấy thực tiễn này được giải thích ở mọi nơi trên web.

+6

Thay đổi các hằng số ở một nơi khác trong mã được đảm bảo hoạt động theo cách này. Nếu ở một nơi khác, ai đó định nghĩa một trong những macro đó, chúng sẽ không bị ghi đè bởi bộ tiền xử lý khi nó phân tích cú pháp tệp này. –

+8

Đó là một ví dụ về nguyên tắc thiết kế WET. – stark

+0

Đã đăng câu trả lời với một ví dụ, hãy thử biên dịch nó. –

Trả lời

132

này cho phép bạn ghi đè các macro khi bạn đang biên soạn:

gcc -DMACRONAME=value 

Các định nghĩa trong file header được sử dụng như mặc định.

17

Tôi không biết ngữ cảnh nhưng điều này có thể được sử dụng để cung cấp cho người dùng tính sẵn có để ghi đè các giá trị được đặt bởi các định nghĩa macro đó. Nếu người dùng xác định rõ ràng giá trị khác nhau cho bất kỳ macro nào trong số đó, macro sẽ được sử dụng thay cho các giá trị được sử dụng tại đây.

Ví dụ: trong g ++, bạn có thể sử dụng cờ -D trong khi biên dịch để chuyển giá trị cho macro.

14

Điều này được thực hiện để người dùng tệp tiêu đề có thể ghi đè các định nghĩa từ mã của người đó hoặc từ cờ -D của trình biên dịch.

7

Bất kỳ dự án C nào đều nằm trên nhiều tệp nguồn. Khi làm việc trên một tệp nguồn duy nhất, các kiểm tra dường như (và thực sự) không có điểm, nhưng khi làm việc trên một dự án C lớn, bạn nên kiểm tra các định nghĩa hiện có trước khi xác định một hằng số. Ý tưởng rất đơn giản: bạn cần hằng số trong tệp nguồn cụ thể đó, nhưng nó có thể đã được định nghĩa trong một tệp khác.

51

Như tôi đã nói trong các bình luận, hãy tưởng tượng tình huống này:

foo.h

#define FOO 4 

defs.h

#ifndef FOO 
#define FOO 6 
#endif 

#ifndef BAR 
#define BAR 4 
#endif 

bar.c

#include "foo.h" 
#include "defs.h" 

#include <stdio.h> 

int main(void) 
{ 
    printf("%d%d", FOO, BAR); 
    return 0; 
} 

Sẽ in 44.

Tuy nhiên, nếu điều kiện ifndef không có ở đó, kết quả sẽ là cảnh báo biên dịch của MACRO định nghĩa lại và nó sẽ in 64.

$ gcc -o bar bar.c 
In file included from bar.c:2:0: 
defs.h:1:0: warning: "FOO" redefined [enabled by default] 
#define FOO 6 
^ 
In file included from bar.c:1:0: 
foo.h:1:0: note: this is the location of the previous definition 
#define FOO 4 
^ 
+1

Đây là trình biên dịch cụ thể. Việc xác định lại một macro giống như đối tượng là bất hợp pháp trừ khi định nghĩa lại là "giống nhau" (có một đặc tả kỹ thuật hơn cho điều đó, nhưng nó không quan trọng ở đây). Mã bất hợp pháp đòi hỏi một chẩn đoán và, đã ban hành một chẩn đoán (ở đây một cảnh báo), trình biên dịch là miễn phí để làm bất cứ điều gì, bao gồm biên dịch mã với kết quả thực hiện cụ thể. –

+7

Nếu bạn có các xung đột đối với cùng một macro, bạn sẽ không * thay * nhận cảnh báo trong hầu hết các trường hợp? Thay vì âm thầm sử dụng định nghĩa đầu tiên (vì định nghĩa thứ hai sử dụng 'ifdef' để tránh định nghĩa lại). –

+0

@PeterCordes Hầu hết các lần, các định nghĩa trong '# infdef' được sử dụng làm giá trị" dự phòng "hoặc" mặc định ". Về cơ bản, "nếu người dùng cấu hình nó, tốt. Nếu không, hãy sử dụng một giá trị mặc định." – Angew

2

Bạn có thể nghĩ về khung/thư viện cung cấp cho người dùng giá trị đặt sẵn mặc định cho phép người dùng biên dịch và làm việc trên đó. Những định nghĩa này được phân phối trong các tệp khác nhau và người dùng cuối cùng được khuyên nên bao gồm tệp config.h của nó, nơi anh có thể định cấu hình các giá trị của nó. Nếu người dùng quên một số xác định hệ thống có thể tiếp tục hoạt động vì cài đặt trước.

1

Sử dụng

#ifndef BEEPTRIM_PITCH_RATE_DEGPS 
#define BEEPTRIM_PITCH_RATE_DEGPS     0.2f 
#endif 

cho phép người dùng để xác định giá trị của các vĩ mô bằng cách sử dụng đối số dòng lệnh (trong gcc/kêu vang/VS) -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f.

Có một lý do quan trọng khác. Đó là lỗi để xác định lại macro tiền xử lý khác nhau. Xem this answer to another SO question. Nếu không có kiểm tra #ifndef, trình biên dịch sẽ tạo ra lỗi nếu -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f được sử dụng làm đối số dòng lệnh trong trình biên dịch.

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