टाइप्डिफ़ और #defines


32

हम सब निश्चित रूप से इस्तेमाल किया है typedefऔर #defineएक ही समय या अन्य है। आज उनके साथ काम करते हुए मैंने एक चीज पर विचार करना शुरू किया।

intएक अन्य नाम के साथ डेटा प्रकार का उपयोग करने के लिए नीचे की 2 स्थितियों पर विचार करें:

typedef int MYINTEGER

तथा

#define MYINTEGER int

ऊपर की स्थिति की तरह, हम कई परिस्थितियों में, बहुत अच्छी तरह से #define का उपयोग करके किसी चीज़ को पूरा कर सकते हैं, और टाइपडिफ का उपयोग करके भी ऐसा ही कर सकते हैं, हालाँकि हम जिस तरीके से करते हैं, वह काफी भिन्न हो सकता है। #define मैक्रो एक्शन भी कर सकता है जो टाइपडिफ नहीं कर सकता।

यद्यपि उनके उपयोग करने का मूल कारण अलग है, उनका कार्य कितना भिन्न है? जब दोनों का उपयोग किया जा सकता है तो दूसरे पर कब प्राथमिकता दी जानी चाहिए? इसके अलावा, क्या कोई गारंटी देता है कि वह किन स्थितियों में दूसरे से तेज है? (उदा #define प्रीप्रोसेसर निर्देश है, इसलिए सब कुछ पहले या संकलन के समय की तरह किया जाता है)।


8
#Define का उपयोग करें कि वे किसके लिए डिज़ाइन किए गए हैं। गुणों के आधार पर सशर्त संकलन जिसे आप कोड लिखते समय नहीं जान सकते (जैसे ओएस / कंपाइलर)। भाषा निर्माण का उपयोग करें अन्यथा।
मार्टिन जॉर्ज

जवाबों:


67

एक typedefआम तौर पर पसंद जब तक कि वहाँ कुछ अजीब कारण यह है कि आप विशेष रूप से एक मैक्रो की जरूरत है है।

मैक्रों पाठ प्रतिस्थापन करते हैं, जो कोड के शब्दार्थों के लिए काफी हिंसा कर सकते हैं। उदाहरण के लिए, दिया गया:

#define MYINTEGER int

आप कानूनी तौर पर लिख सकते हैं:

short MYINTEGER x = 42;

क्योंकि short MYINTEGERकरने के लिए फैलता है short int

दूसरी ओर, एक टंकण के साथ:

typedef int MYINTEGER:

नाम MYINTEGERइस प्रकार का दूसरा नाम है int, न कि कीवर्ड "int" के लिए एक पाठीय प्रतिस्थापन।

अधिक जटिल प्रकारों के साथ चीजें और भी खराब हो जाती हैं। उदाहरण के लिए, यह दिया गया:

typedef char *char_ptr;
char_ptr a, b;
#define CHAR_PTR char*
CHAR_PTR c, d;

a, bऔर cसभी संकेत हैं, लेकिन dएक है char, क्योंकि अंतिम पंक्ति का विस्तार है:

char* c, d;

के बराबर है

char *c;
char d;

(पॉइंटर प्रकारों के लिए आमतौर पर एक अच्छा विचार नहीं है, लेकिन यह इस बिंदु को दिखाता है।)

एक और अजीब मामला:

#define DWORD long
DWORD double x;     /* Huh? */

1
दोषियों को फिर से दोष देने के लिए! :) संकेत के अलावा कोई अन्य उदाहरण जहां इस तरह के मैक्रोज़ का उपयोग करना नासमझी है?
c0da

2
ऐसा नहीं है कि मैं कभी भी एक के स्थान पर एक मैक्रो का उपयोग करना चाहते typedefहैं, लेकिन उचित तरीके से उस मैक्रो तर्कों का उपयोग करने के लिए है जो कुछ इस प्रकार के साथ कुछ करता है निर्माण करने के लिए: #define CHAR_PTR(x) char *x। यह कम से कम कंपाइलर को गलत तरीके से उपयोग करने पर कंपित का कारण बनेगा।
ब्लरफाल

1
मत भूलना:const CHAR_PTR mutable_pointer_to_const_char; const char_ptr const_pointer_to_mutable_char;
जॉन Purdy

3
परिभाषित करने से त्रुटि संदेश भी समझ से बाहर हो जाते हैं
थॉमस बोनिनी

दर्द का एक उदाहरण जो मैक्रोज़ के दुरुपयोग का कारण बन सकता है (हालांकि मैक्रोज़ बनाम टाइपडेफ़्स के लिए सीधे प्रासंगिक नहीं): github.com/Keith-S-Tompson/42
कीथ थॉम्पसन

15

अब तक, मैक्रोज़ के साथ सबसे बड़ी समस्या यह है कि उन्हें स्कूप नहीं किया जाता है। यह अकेला ही टाइम्डिफ के उपयोग का वारंट करता है। साथ ही, यह शब्दार्थ से अधिक स्पष्ट है। जब कोई व्यक्ति जो आपके कोड को पढ़ता है वह एक परिभाषित देखता है, तो वह यह नहीं जान पाएगा कि जब तक वह इसे पढ़ता है और पूरे मैक्रो को समझ नहीं पाता है। एक टंकणकार पाठक को बताता है कि एक प्रकार का नाम परिभाषित किया जाएगा। (मुझे यह उल्लेख करना चाहिए कि मैं सी ++ के बारे में बात कर रहा हूं। मैं सी के लिए टाइप किए गए स्कूपिंग के बारे में निश्चित नहीं हूं, लेकिन मुझे लगता है कि यह समान है)।


लेकिन जैसा कि मैंने प्रश्न में प्रदान किए गए उदाहरण में दिखाया है, एक टाइप्डेफ़ और #define शब्दों की समान संख्या का उपयोग करते हैं! इसके अलावा, मैक्रो के इन 3 शब्दों के कारण कोई भ्रम नहीं होगा, क्योंकि शब्द समान हैं, लेकिन सिर्फ पुनर्व्यवस्थित हैं। :)
c0da

2
हां, लेकिन यह लघुता के बारे में नहीं है। एक मैक्रो टंकण के अलावा एक अन्य काम कर सकता है। लेकिन व्यक्तिगत रूप से मुझे लगता है कि स्कूपिंग सबसे महत्वपूर्ण है।
तमसे सजेलेई

2
@ c0da - आपको टाइपसीफ्स के लिए मैक्रोज़ का उपयोग नहीं करना चाहिए, आपको टाइपडेफ़्स के लिए टाइपराइफ़ का उपयोग करना चाहिए। मैक्रो का वास्तविक प्रभाव बहुत अलग हो सकता है, जैसा कि विभिन्न प्रतिक्रियाओं द्वारा चित्रित किया गया है।
जॉरिस टिम्मरमन्स

15

स्रोत कोड मुख्य रूप से साथी डेवलपर्स के लिए लिखा गया है। कंप्यूटर इसके संकलित संस्करण का उपयोग करते हैं।

इस परिप्रेक्ष्य typedefमें एक अर्थ है कि #defineनहीं करता है।


6

कीथ थॉम्पसन का जवाब बहुत अच्छा है और साथ में स्कैम के बारे में तमसे सजेले के अतिरिक्त बिंदुओं को आपकी ज़रूरत की सभी पृष्ठभूमि प्रदान करनी चाहिए।

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


5

पहले से दी गई गुंजाइश और पाठ प्रतिस्थापन के बारे में सभी मान्य टिप्पणियों के अलावा, #define भी पूरी तरह से typedef के साथ संगत नहीं है! अर्थात् जब यह फ़ंक्शन पॉइंटर्स के मामले में आता है।

typedef void(*fptr_t)(void);

यह एक प्रकार की घोषणा करता है fptr_tजो प्रकार के एक फ़ंक्शन के लिए एक संकेतक है void func(void)

आप मैक्रो के साथ इस प्रकार की घोषणा नहीं कर सकते। #define fptr_t void(*)(void)जाहिर है काम नहीं करेगा। आपको कुछ अस्पष्ट लिखना होगा #define fptr_t(name) void(*name)(void), जो वास्तव में सी भाषा में कोई मतलब नहीं रखता है, जहां हमारे पास कोई रचनाकार नहीं है।

ऐरे पॉइंटर्स को #define के साथ घोषित नहीं किया जा सकता है: typedef int(*arr_ptr)[10];


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


1
इससे भी बेहतर फ़ंक्शन और एरे पॉइंटर्स का संयोजन है, जैसे char *(*(*foo())[])();( fooएक फ़ंक्शन पॉइंटर को पॉइंटर्स की एक सरणी पर लौटाता है जो पॉइंटर को वापस लौटाता है char)।
जॉन Bode

4

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


2

परिभाषित के खिलाफ सामान्य तर्कों से परे, आप मैक्रोज़ का उपयोग करके इस फ़ंक्शन को कैसे लिखेंगे?

template <typename IterType>
typename IterType::value_type Sum(
    const IterType& begin, 
    const IterType& end, 
    const IterType::value_type& initialValue)
{
    typename IterType::value_type result = initialValue;
    for (IterType i = begin; i != end; ++i)
        result += i;

    return result;
}

....

vector<int> values;
int sum = Sum(values.begin(), values.end(), 0);

यह स्पष्ट रूप से एक तुच्छ उदाहरण है, लेकिन यह फ़ंक्शन किसी प्रकार के आगे चलने योग्य अनुक्रम को जोड़ सकता है जो इसके अलावा को लागू करता है *। इस तरह से इस्तेमाल किए जाने वाले टाइपफेड जेनेरिक प्रोग्रामिंग के एक महत्वपूर्ण तत्व हैं ।

* मैंने अभी इसे यहाँ लिखा है, मैं इसे पाठक के लिए एक एक्सर्साइज़ के रूप में संकलित करना छोड़ता हूं :-)

संपादित करें:

यह उत्तर बहुत भ्रम पैदा करता है, इसलिए मुझे इसे और अधिक आकर्षित करने दें। यदि आप एसटीएल वेक्टर की परिभाषा के अंदर देखना चाहते थे, तो आपको निम्नलिखित के समान कुछ दिखाई देगा:

template <typename ValueType, typename AllocatorType>
class vector
{
public:
    typedef ValueType value_type;
...
}

मानक कंटेनरों के भीतर टाइपडिफ्स का उपयोग इन प्रकारों को संदर्भित करने के लिए एक जेनेरिक फ़ंक्शन (जैसे मैं ऊपर बनाया गया) की अनुमति देता है। फ़ंक्शन "सम" कंटेनर के प्रकार ( std::vector<int>) पर रखा गया है, कंटेनर के अंदर रखे हुए प्रकार पर नहीं ( int)। बिना टाइपराइफ के उस आंतरिक प्रकार को संदर्भित करना संभव नहीं होगा।

इसलिए, टाइप-सीड्स आधुनिक C ++ के लिए केंद्रीय हैं और यह मैक्रोज़ के साथ संभव नहीं है।


मैक्रोज़ बनाम typedef, मैक्रोज़ बनाम इनलाइन फ़ंक्शंस के बारे में पूछा गया प्रश्न ।
बेन वोइगट

ज़रूर, और यह केवल टाइपडिफ्स के साथ संभव है ... जो कि value_type है।
क्रिस पिटमैन

यह एक टाइप्डिफ नहीं है, यह टेम्प्लेट प्रोग्रामिंग है। एक फ़ंक्शन या फ़ंक्टर एक प्रकार नहीं है, चाहे वह कितना भी सामान्य हो।

@ लुंडिन मैंने और विवरण जोड़ दिए हैं: फ़ंक्शन सम केवल इसलिए संभव है क्योंकि मानक कंटेनर टाइप किए गए प्रकारों का उपयोग करते हैं ताकि वे उन प्रकारों को उजागर कर सकें, जिन पर वे विस्थापित हैं। मैं यह नहीं कह रहा हूं कि सुम एक टाइपफेड है। मैं कह रहा हूँ std :: वेक्टर <T> :: value_type एक टाइपफ़ेड है। सत्यापित करने के लिए किसी भी मानक पुस्तकालय कार्यान्वयन के स्रोत को देखने के लिए स्वतंत्र महसूस करें।
क्रिस पिटमैन

काफी उचित। शायद केवल दूसरे स्निपेट को पोस्ट करना बेहतर होता।

1

typedefसी ++ दर्शन फिट बैठता है: संकलन समय में सभी संभव जांच / जोर। #defineसिर्फ एक प्रीप्रोसेसर चाल है जो संकलक के बहुत सारे अर्थ को छिपाता है। आपको कोड शुद्धता से अधिक संकलन प्रदर्शन के बारे में चिंता नहीं करनी चाहिए।

जब आप एक नया प्रकार बनाते हैं तो आप एक नई "चीज़" को परिभाषित कर रहे होते हैं जो आपके प्रोग्राम के डोमेन में हेरफेर करता है। तो आप इस "चीज़" का उपयोग फ़ंक्शंस और क्लासेस बनाने के लिए कर सकते हैं, और आप अपने लाभ के लिए कंपाइलर का उपयोग स्टैटिक चेक करने के लिए कर सकते हैं। वैसे भी, जैसा कि C ++ C के साथ संगत है, बहुत सारे अंतर्निहित intऔर अंतर -आधारित प्रकार हैं जो चेतावनी उत्पन्न नहीं करते हैं। इसलिए आपको इस मामले में स्थैतिक जाँच की पूरी शक्ति नहीं मिलती है। लेकिन, आप अपने को बदलने सकता है typedefएक साथ enumअंतर्निहित रूपांतरण ढूंढ़ने के लिए। उदाहरण के लिए: अगर आपने typedef int Age;, तो आप के साथ की जगह ले सकता enum Age { };है और आप के बीच निहित रूपांतरण के आधार पर त्रुटियों के सभी प्रकार के विवरण मिलेंगे Ageऔर int

एक और बात: typedefएक अंदर हो सकता है namespace


1

टंकण के बजाय परिभाषित का उपयोग करना एक और महत्वपूर्ण पहलू के तहत परेशान कर रहा है, और प्रकार लक्षण की अवधारणा। विभिन्न वर्गों (मानक कंटेनरों के बारे में सोचें) पर विचार करें, जिनमें से सभी अपने विशिष्ट टाइपडिफ़ को परिभाषित करते हैं। आप जेनेरिक कोड को टाइपराइफ के संदर्भ में लिख सकते हैं। इसके उदाहरणों में सामान्य कंटेनर आवश्यकताएं शामिल हैं (c ++ मानक 23.2.1 [कंटेन.requirements.general] जैसे

X::value_type
X::reference
X::difference_type
X::size_type

यह सब मैक्रो के साथ सामान्य तरीके से व्यक्त नहीं है क्योंकि यह स्कूप नहीं है।


1

अपने डीबगर में इसके निहितार्थ को न भूलें। कुछ डीबगर #define को बहुत अच्छी तरह से हैंडल नहीं करते हैं। आपके द्वारा उपयोग किए जाने वाले डीबगर में दोनों के साथ खेलें। याद रखें, आप इसे लिखने से ज्यादा समय इसे पढ़ने में बिताएंगे।


-2

"#define" आपके द्वारा लिखे जाने के बाद लिखी गई चीज़ों को बदल देगा। इसलिए अगर आप कस्टोम टाइप करना चाहते हैं - टाइपडिफ का इस्तेमाल करें। यदि आपको मैक्रोज़ की आवश्यकता है - परिभाषित का उपयोग करें।


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