ऑब्जेक्टिव-सी में # डेफिन बनाम कास्ट


81

मैं ऑब्जेक्टिव-सी के लिए नया हूं, और मेरे पास constऔर प्रीप्रोसेसिंग निर्देश के बारे में कुछ सवाल हैं #define

सबसे पहले, मैंने पाया कि निरंतर उपयोग के प्रकार को परिभाषित करना संभव नहीं है #define। ऐसा क्यों है?

दूसरा, क्या उनमें से किसी एक को दूसरे पर इस्तेमाल करने के कोई फायदे हैं?

अंत में, कौन सा तरीका अधिक कुशल और / या अधिक सुरक्षित है?

जवाबों:


107

सबसे पहले, मैंने पाया कि इसकी #define का उपयोग करके निरंतर के प्रकार को परिभाषित करना संभव नहीं है, ऐसा क्यों है?

क्यों क्या है? यह सच नहीं है:

#define MY_INT_CONSTANT ((int) 12345)

दूसरा, क्या उनमें से किसी एक को दूसरे पर इस्तेमाल करने के कोई फायदे हैं?

हाँ। #defineएक मैक्रो को परिभाषित करता है जिसे संकलन शुरू होने से पहले ही बदल दिया जाता है। constयदि आप इसे बदलने का प्रयास करते हैं तो कंपाइलर एक चर को संशोधित करता है, ताकि कंपाइलर एक त्रुटि को चिह्नित करेगा। ऐसे संदर्भ हैं जिनमें आप उपयोग कर सकते हैं #defineलेकिन आप एक का उपयोग नहीं कर सकते हैं const(हालांकि मैं नवीनतम क्लैंग का उपयोग करके खोजने के लिए संघर्ष कर रहा हूं)। सिद्धांत रूप constमें, निष्पादन में जगह लेता है और स्मृति के संदर्भ की आवश्यकता होती है, लेकिन व्यवहार में यह महत्वहीन है और संकलक द्वारा दूर अनुकूलित किया जा सकता है।

consts तुलना में अधिक संकलक और डिबगर के अनुकूल हैं #define। ज्यादातर मामलों में, यह ओवरराइडिंग बिंदु है जिस पर आपको निर्णय लेना चाहिए, जिस पर उपयोग करना है।

सिर्फ एक संदर्भ के बारे में सोचा है जिसमें आप उपयोग कर सकते हैं #defineलेकिन नहीं const। यदि आपके पास एक स्थिरांक है जिसे आप बहुत सारी .cफाइलों में उपयोग करना चाहते हैं , #defineतो आप इसे हेडर में चिपका सकते हैं। constआप के साथ एक सी फ़ाइल में एक परिभाषा है और

// in a C file
const int MY_INT_CONST = 12345;

// in a header
extern const int MY_INT_CONST;

एक हेडर में। MY_INT_CONSTकिसी भी सी फ़ाइल में एक स्थिर या वैश्विक स्कोप सरणी के आकार के रूप में इस्तेमाल नहीं किया जा सकता है, सिवाय इसके कि इसमें कोई भी परिभाषित नहीं है।

हालाँकि, पूर्णांक स्थिरांक के लिए आप एक का उपयोग कर सकते हैं enum। वास्तव में ऐसा ही है जो Apple लगभग हमेशा करता है। इसमें #defines और consts दोनों के सभी फायदे हैं लेकिन केवल पूर्णांक स्थिरांक के लिए काम करता है।

// In a header
enum
{
    MY_INT_CONST = 12345,
};

अंत में, कौन सा तरीका अधिक कुशल और / या अधिक सुरक्षित है?

#defineहालांकि सिद्धांत में अधिक कुशल है, जैसा कि मैंने कहा, आधुनिक संकलक शायद यह सुनिश्चित करते हैं कि थोड़ा अंतर है। #defineइसमें अधिक सुरक्षित है कि इसे असाइन करने का प्रयास करने के लिए हमेशा एक संकलक त्रुटि होती है

#define FOO 5

// ....

FOO = 6;   // Always a syntax error

constसंकलक चेतावनी जारी कर सकता है, हालांकि सौंपा जा रहा है में धोखा दिया जा सकता है:

const int FOO = 5;

// ...

(int) FOO = 6;     // Can make this compile

प्लेटफ़ॉर्म के आधार पर, असाइनमेंट अभी भी रन टाइम पर विफल हो सकता है यदि स्थिर को केवल एक सेगमेंट में रखा जाता है और यह सी मानक के अनुसार आधिकारिक रूप से अपरिभाषित व्यवहार है।

व्यक्तिगत रूप से, पूर्णांक स्थिरांक के लिए, मैं हमेशा enumअन्य प्रकार के स्थिरांक के लिए एस का उपयोग करता हूं, मैं constतब तक उपयोग करता हूं जब तक मेरे पास बहुत अच्छा कारण नहीं है।


मैं जानता हूँ कि यह पुरानी है, लेकिन एक उदाहरण है जहाँ आप एक स्थिरांक आप एक परिभाषित इस्तेमाल कर सकते हैं कि उपयोग नहीं कर सकते है "#define MY_NSNUM_CONSTANT @ 5" जो का उपयोग नहीं किया जा सकता है "NSNumber * स्थिरांक MY_NSNUM_CONSTANT = @ 5"
shortstuffsushi

मेरा तर्क है कि #define कांस्टेबल की तुलना में निष्पादन में अधिक स्थान लेता है। एक कास्ट को एक बार संग्रहीत किया जाता है, लेकिन हर बार जब आप इसका उपयोग करते हैं तो एक #define को गुणा किया जाता है क्योंकि यह सिर्फ पाठ प्रतिस्थापन है। लेकिन चूंकि यह अंतर महत्वहीन है, इसलिए मुझे अनावश्यक रूप से पांडित्य हो रहा है।
रयान बैलेनटाइन

@RyanBallantyne मुझे लगता है कि आप स्ट्रिंग स्थिरांक जैसी चीजों के लिए सही हो सकते हैं, लेकिन पूर्णांक स्थिरांक के लिए नहीं क्योंकि यहां तक ​​कि आप स्थिरांक को एक स्थान पर संग्रहीत करते हैं, इसे एक्सेस करने के लिए आपको इसके पते की आवश्यकता होती है जो कम से कम एक के रूप में बड़ा है int। मुझे बहुत आश्चर्य होगा, हालांकि, अगर यह एक आधुनिक संकलक में बिल्कुल भी अंतर करता है।
जेरेमीप

16

एक सी कोडर से:

A constबस एक परिवर्तनशील है जिसकी सामग्री को बदला नहीं जा सकता है।

#define name valueबहरहाल, एक पूर्वप्रक्रमक आदेश के सभी उदाहरणों की जगह है nameके साथ value

उदाहरण के लिए, यदि आप #define defTest 5, defTestआपके कोड के सभी उदाहरणों को आपके 5संकलन के साथ बदल दिया जाएगा ।


11

यह महत्वपूर्ण है कि #define और const निर्देश के बीच अंतर को समझना जो कि समान चीजों के लिए नहीं हैं।

const

constएक प्रकार से ऑब्जेक्ट को उत्पन्न करने के लिए उपयोग किया जाता है, जो कि एक बार शुरू होने, स्थिर होने पर होगा। इसका मतलब है कि यह प्रोग्राम मेमोरी में एक ऑब्जेक्ट है और इसे आसानी से उपयोग किया जा सकता है। हर बार जब प्रोग्राम लॉन्च किया जाता है, तो ऑब्जेक्ट उत्पन्न होता है।

#define

#defineकोड पठनीयता और भविष्य के संशोधनों को कम करने के लिए उपयोग किया जाता है। एक परिभाषित का उपयोग करते समय, आप केवल एक नाम के पीछे एक मान मुखौटा करते हैं। इसलिए जब एक आयत के साथ काम करते हैं तो आप संबंधित मानों के साथ चौड़ाई और ऊंचाई को परिभाषित कर सकते हैं। फिर कोड में, पढ़ना आसान होगा क्योंकि संख्या के बजाय नाम होंगे।

यदि बाद में आप चौड़ाई के लिए मूल्य बदलने का निर्णय लेते हैं, तो आपको अपनी पूरी फ़ाइल में एक उबाऊ और खतरनाक खोज / प्रतिस्थापन के बजाय केवल इसे परिभाषित में बदलना होगा। संकलन करते समय, प्रीप्रोसेसर सभी निर्धारित नाम को कोड में मानों से बदल देगा। इसलिए, उनका उपयोग करने में कोई समय नहीं गंवाया जाता है।


7

अन्य लोगों की टिप्पणियों के अलावा, उपयोग करने में त्रुटियाँ #defineडीबग करने के लिए बेहद मुश्किल हैं क्योंकि प्री-प्रोसेसर कंपाइलर से पहले उन्हें पकड़ लेता है।


3

चूंकि प्री-प्रोसीजर के निर्देश पर ध्यान दिया जाता है, इसलिए मैं सुझाव देता हूं कि ए const। आप पूर्व-प्रोसेसर के साथ एक प्रकार निर्दिष्ट नहीं कर सकते क्योंकि संकलन से पहले एक पूर्व-प्रोसेसर निर्देश हल किया गया है। ठीक है, आप कर सकते हैं, लेकिन कुछ इस तरह:

#define DEFINE_INT(name,value) const int name = value;

और इसका उपयोग करें

DEFINE_INT(x,42) 

जो संकलक द्वारा देखा जाएगा

const int x = 42;

सबसे पहले, मैंने पाया कि इसकी #define का उपयोग करके निरंतर के प्रकार को परिभाषित करना संभव नहीं है, ऐसा क्यों है?

आप मेरी पहली स्निपेट देख सकते हैं।

दूसरा, क्या उनमें से किसी एक को दूसरे पर इस्तेमाल करने के कोई फायदे हैं?

आमतौर पर constप्री-प्रोसेसर निर्देश के बजाय डिबगिंग में मदद करता है, इस मामले में उतना नहीं (लेकिन फिर भी करता है)।

अंत में, कौन सा तरीका अधिक कुशल और / या अधिक सुरक्षित है?

दोनों ही उतने ही कुशल हैं। मेरा कहना है कि मैक्रो संभावित रूप से अधिक सुरक्षित हो सकता है क्योंकि रन-टाइम के दौरान इसे बदला नहीं जा सकता है, जबकि एक चर हो सकता है।


const ...मैक्रो का उपयोग करने के बजाय सिर्फ टाइप क्यों करें ?
एड हील

1
@EdHeal नहीं मैं सिर्फ यह कह रहा था कि आप "मैंने पाया कि इसके जवाब में #define का उपयोग करके निरंतर के प्रकार को परिभाषित करना संभव नहीं है, ऐसा क्यों है?"
लुचियन ग्रिगोर

1
> pre-processor directives are frowned upon[उद्धरण वांछित]
बेन लेगिएरो

मुझे लगता है कि आप इस प्रकार का उपयोग कर सकते हैं: #define myValue ((डबल) 2)। जैसा कि मैं इसे समझता हूं, प्रीप्रोसेसर केवल "myValue" को बदल देगा, परिभाषित विवरण में इसके बाद क्या आता है, टाइप जानकारी सहित।
vomako

1

मैंने एक विधि से अधिक विधियों को बनाने में मदद करने से पहले #define का उपयोग किया है जैसे कि मेरे पास कुछ है।

 // This method takes up to 4 numbers, we don't care what the method does with these numbers.
 void doSomeCalculationWithMultipleNumbers:(NSNumber *)num1 Number2:(NSNumber *)num2 Number3:(NSNumber *)num23 Number3:(NSNumber *)num3;

लेकिन मेरे पास ऐसी विधि भी है जो केवल 3 संख्याएँ और 2 संख्याएँ लेती है इसलिए दो नई पद्धतियाँ लिखने के बजाय मैं #define का उपयोग करके उसी का उपयोग करने जा रहा हूँ, जैसे।

 #define doCalculationWithFourNumbers(num1, num2, num3, num4) \
         doSomeCalculationWithMultipleNumbers((num1), (num2), (num3), (num4))

 #define doCalculationWithThreeNumbers(num1, num2, num3) \
         doSomeCalculationWithMultipleNumbers((num1), (num2), (num3), nil)

 #define doCalculationWithTwoNumbers(num1, num2) \
         doSomeCalculationWithMultipleNumbers((num1), (num2), nil, nil)

मुझे लगता है कि यह एक बहुत अच्छी बात है, मुझे पता है कि आप सीधे तरीके से जा सकते हैं और बस उन रिक्त स्थान पर नील डाल सकते हैं जो आप नहीं चाहते हैं लेकिन अगर आप एक पुस्तकालय का निर्माण कर रहे हैं तो यह बहुत उपयोगी है। इसके अलावा यह कैसे है

     NSLocalizedString(<#key#>, <#comment#>)
     NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>)
     NSLocalizedStringFromTableInBundle(<#key#>, <#tbl#>, <#bundle#>, <#comment#>)

कार्य पूर्ण।

जबकि मुझे विश्वास नहीं है कि आप स्थिरांक के साथ ऐसा कर सकते हैं। लेकिन स्थिरांक का #Dfine पर लाभ होता है जैसे आप #define के साथ एक प्रकार निर्दिष्ट नहीं कर सकते क्योंकि यह एक पूर्व-प्रोसेसर निर्देश है जिसे संकलन से पहले हल किया जाता है, और यदि आपको #define के साथ कोई त्रुटि मिलती है तो वे डीबग करना कठिन हैं लगातार। दोनों के लाभ और चढ़ाव हैं, लेकिन मैं कहूंगा कि यह सब उस प्रोग्रामर पर निर्भर करता है, जिसे आपने उपयोग करने का फैसला किया है। मैंने उन दोनों के साथ एक लाइब्रेरी लिखी है, जो कि मैंने जो दिखाया है, उसे करने के लिए #define का उपयोग करते हुए और निरंतर चर घोषित करने के लिए स्थिर रहता है, जिस पर मुझे एक प्रकार निर्दिष्ट करने की आवश्यकता होती है।

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