अगर यह पहले से ही परिभाषित नहीं है तो केवल एक मैक्रो को क्यों परिभाषित करें?


93

हमारे सभी सी कोड बेस में, मुझे लगता है कि प्रत्येक मैक्रो निम्नलिखित तरीके से परिभाषित किया गया है:

#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

सिर्फ मैक्रोज़ को परिभाषित करने के बजाय इन परिभाषित जाँचों को करने का औचित्य क्या है?

#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

मैं इस प्रथा को वेब पर कहीं भी स्पष्ट नहीं कर सकता।


6
कोड में कहीं और स्थिरांक बदलना इस तरह से काम करने की गारंटी है। अगर कहीं और कोई उन मैक्रोज़ में से किसी एक को परिभाषित करता है, तो वे प्रीप्रोसेसर द्वारा अधिलेखित नहीं होंगे जब वह इस फ़ाइल को पार्स करता है।
एनजो फेरबर

8
यह WET डिजाइन सिद्धांत का एक उदाहरण है।
स्टार्क

एक उदाहरण के साथ एक उत्तर पोस्ट करें, इसे संकलित करने का प्रयास करें।
एन्ज़ो फेरबर

जवाबों:


141

जब आप संकलन कर रहे हों तो यह आपको मैक्रोज़ को ओवरराइड करने की अनुमति देता है:

gcc -DMACRONAME=value

हेडर फ़ाइल में परिभाषाएँ डिफॉल्ट के रूप में उपयोग की जाती हैं।


51

जैसा कि मैंने टिप्पणी में कहा, इस स्थिति की कल्पना करें:

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;
}

छपेगा 44

हालांकि, अगर सशर्त ifndefनहीं था, तो परिणाम एमएसीआरओ पुनर्वितरण का संकलन चेतावनी होगा और यह प्रिंट होगा 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
यह संकलक-विशिष्ट है। ऑब्जेक्ट-जैसे मैक्रो को फिर से परिभाषित करना तब तक गैरकानूनी है जब तक कि पुनर्वितरण "समान" न हो (इसके लिए एक अधिक तकनीकी विनिर्देश है, लेकिन यह यहां महत्वपूर्ण नहीं है)। अवैध कोड के लिए एक नैदानिक ​​की आवश्यकता होती है और, एक नैदानिक ​​(यहां एक चेतावनी) जारी करने के बाद, कंपाइलर कुछ भी करने के लिए स्वतंत्र है, जिसमें कार्यान्वयन-विशिष्ट परिणामों के साथ कोड को संकलित करना शामिल है।
पीट बेकर

7
आप एक ही मैक्रो के लिए defs परस्पर विरोधी है, नहीं आप चाहते हैं बल्कि ज्यादातर मामलों में चेतावनी मिलती है? पहली परिभाषा का उपयोग करने के बजाय चुपचाप (क्योंकि दूसरा एक ifdefपुनर्परिभाषित से बचने के लिए उपयोग करता है )।
पीटर कॉर्ड्स

@PeterCordes अधिकांश समय, परिभाषा के तहत #infdef"फ़ॉलबैक" या "डिफ़ॉल्ट" मान के रूप में उपयोग किया जाता है। मूल रूप से, "यदि उपयोगकर्ता ने इसे कॉन्फ़िगर किया है, तो ठीक है। यदि नहीं, तो एक डिफ़ॉल्ट मान का उपयोग करें।"
Angew को अब SO

@Angew: ठीक है, इसलिए यदि आपके पास #definesलाइब्रेरी हैडर में से कुछ हैं जो लाइब्रेरी के ABI का हिस्सा हैं , तो आपको उसमें लपेटना नहीं चाहिए #ifndef। (या बेहतर, उपयोग करें enum)। मैं सिर्फ यह स्पष्ट करना चाहता था कि #ifndefएक संकलन इकाई में किसी चीज़ के लिए कस्टम परिभाषा होने पर ही उचित है, लेकिन दूसरा ठीक नहीं है। यदि a.cकिसी भिन्न क्रम में हेडर शामिल हैं b.c, तो उन्हें अलग-अलग परिभाषा मिल सकती है max(a,b), और उन परिभाषाओं में से एक के साथ टूट सकता है max(i++, x), लेकिन दूसरा GNU स्टेटमेंट-एक्सप्रेशन में अस्थायी का उपयोग कर सकता है। अभी भी कम से कम भ्रमित!
पीटर कॉर्ड्स

@PeterCordes मुझे उस मामले में क्या करना पसंद है#ifdef FOO #error FOO already defined! #endif #define FOO x
कोल जॉनसन

17

मुझे संदर्भ नहीं पता है लेकिन इसका उपयोग उपयोगकर्ता को उन स्थूल परिभाषाओं द्वारा निर्धारित मूल्यों को ओवरराइड करने के लिए उपलब्धता प्रदान करने के लिए किया जा सकता है। यदि उपयोगकर्ता स्पष्ट रूप से उन मैक्रोज़ में से किसी के लिए एक अलग मान निर्धारित करता है, तो इसका उपयोग यहां उपयोग किए गए मानों के बजाय किया जाएगा।

उदाहरण के लिए g ++ में आप -Dकिसी मैक्रो को मान देने के लिए संकलन के दौरान ध्वज का उपयोग कर सकते हैं ।


14

ऐसा इसलिए किया जाता है ताकि हेडर फ़ाइल का उपयोगकर्ता अपने कोड से या कंपाइलर -D फ्लैग से परिभाषाओं को ओवरराइड कर सके।


7

कोई भी सी परियोजना कई स्रोत फ़ाइलों पर रहती है। जब एक एकल स्रोत फ़ाइल पर काम करते हैं, तो चेक (और वास्तव में) का कोई मतलब नहीं होता है, लेकिन जब एक बड़े सी प्रोजेक्ट पर काम करते हैं, तो एक निरंतरता को परिभाषित करने से पहले मौजूदा परिभाषित करने के लिए जांच करना एक अच्छा अभ्यास है। यह विचार सरल है: आपको उस विशिष्ट स्रोत फ़ाइल में स्थिरांक की आवश्यकता है, लेकिन यह पहले से ही दूसरे में परिभाषित हो सकता है।


2

आप एक ऐसे ढांचे / पुस्तकालय के बारे में सोच सकते हैं जो उपयोगकर्ता को एक डिफ़ॉल्ट प्रीसेट देता है जो उपयोगकर्ता को उस पर संकलन और काम करने की अनुमति देता है। वे परिभाषित अलग-अलग फ़ाइलों में फैले हुए हैं और अंतिम उपयोगकर्ता को सलाह दी जाती है कि वह इसे config.h फ़ाइल में शामिल करे जहाँ वह अपने मूल्यों को कॉन्फ़िगर कर सके। यदि उपयोगकर्ता कुछ परिभाषित करता है तो सिस्टम प्रीसेट के कारण काम करना जारी रख सकता है।


1

का उपयोग करते हुए

#ifndef BEEPTRIM_PITCH_RATE_DEGPS
#define BEEPTRIM_PITCH_RATE_DEGPS                   0.2f
#endif

उपयोगकर्ता को कमांड लाइन तर्क (gcc / clang / VS) का उपयोग करके मैक्रो के मान को परिभाषित करने की अनुमति देता है -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f

एक और महत्वपूर्ण कारण है। यह एक पूर्ववर्ती मैक्रो को अलग-अलग तरीके से फिर से परिभाषित करने के लिए एक त्रुटि है। एक और SO प्रश्न का यह उत्तर देखें । #ifndefजांच के बिना , -DBEEPTRIM_PITCH_RATE_DEGPS=0.3fकंपाइलर के मंगलाचरण में कमांड लाइन तर्क के रूप में उपयोग किए जाने पर कंपाइलर को एक त्रुटि उत्पन्न करनी चाहिए ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.