C Language
typedef
खोज…
परिचय
typedef
तंत्र अन्य प्रकारों के लिए उपनाम बनाने की अनुमति देता है। यह नए प्रकार का निर्माण नहीं करता है। लोग अक्सर संरचना या संघ प्रकारों को उपनाम देने के लिए, या फ़ंक्शन (या फ़ंक्शन पॉइंटर) प्रकारों के लिए उपनाम बनाने के लिए, कोड की पोर्टेबिलिटी में सुधार करने के लिए typedef
का उपयोग करते हैं।
सी मानक में, typedef
को सुविधा के लिए 'भंडारण वर्ग' के रूप में वर्गीकृत किया गया है; यह वाक्यात्मक रूप से होता है जहां भंडारण वर्ग जैसे कि static
या extern
दिखाई दे सकते हैं।
वाक्य - विन्यास
- typedef मौजूदा_नाम alias_name;
टिप्पणियों
टंकण का नुकसान
typedef
सीड बड़े सी कार्यक्रमों में नेमस्पेस के प्रदूषण को जन्म दे सकता है।
टंकण संरचनाओं के नुकसान
इसके अलावा, एक टैग नाम के बिना typedef
की संरचनाएं हेडर फ़ाइलों के बीच संबंधों को आदेश देने के लिए अनावश्यक आवश्यकता का एक प्रमुख कारण हैं।
विचार करें:
#ifndef FOO_H
#define FOO_H 1
#define FOO_DEF (0xDEADBABE)
struct bar; /* forward declaration, defined in bar.h*/
struct foo {
struct bar *bar;
};
#endif
इस तरह की परिभाषा के साथ, typedefs
का उपयोग नहीं करते typedefs
, FOO_DEF
परिभाषा में प्राप्त करने के लिए foo.h
को शामिल करना एक संकलन इकाई के लिए संभव है। अगर यह foo
स्ट्रक्चर के bar
मेंबर को bar.h
करने की कोशिश नहीं करता है, तो bar.h
फाइल को शामिल करने की कोई जरूरत नहीं होगी।
टाइप्डिफ़ बनाम #define
#define
एक सी प्री-प्रोसेसर निर्देश है जिसका उपयोग typedef
समान विभिन्न डेटा प्रकारों के लिए उपनामों को परिभाषित करने के लिए भी किया जाता है लेकिन निम्नलिखित अंतरों के साथ:
typedef
केवल उन प्रकारों को प्रतीकात्मक नाम देने तक सीमित है, जहां#define
का उपयोग मूल्यों के लिए उपनाम को परिभाषित करने के लिए किया जा सकता है।typedef
व्याख्या कंपाइलर द्वारा की जाती है जबकि#define
स्टेटमेंट प्री-प्रोसेसर द्वारा प्रोसेस की जाती है।ध्यान दें कि
#define cptr char *
बादcptr a, b;
typedef char *cptr;
जैसा नहीं करता हैtypedef char *cptr;
इसके बादcptr a, b;
।#define
साथ,b
एक सादाchar
चर है, लेकिन यहtypedef
साथ एक सूचक भी है।
संरचनाओं और यूनियनों के लिए टंकण
आप किसी struct
को अन्य नाम दे सकते हैं:
typedef struct Person {
char name[32];
int age;
} Person;
Person person;
Structs घोषित करने के पारंपरिक तरीके की तुलना में, प्रोग्रामर है की जरूरत नहीं होगी struct
हर बार वे कहते हैं कि struct का एक उदाहरण घोषणा करते हैं।
ध्यान दें कि अंतिम अर्धविराम तक Person
(जैसा कि struct Person
विपरीत) को परिभाषित नहीं किया गया है। इस प्रकार लिंक की गई सूचियों और पेड़ों की संरचनाओं के लिए जो एक ही संरचना प्रकार के लिए एक पॉइंटर को शामिल करने की आवश्यकता है, आपको या तो उपयोग करना होगा:
typedef struct Person {
char name[32];
int age;
struct Person *next;
} Person;
या:
typedef struct Person Person;
struct Person {
char name[32];
int age;
Person *next;
};
एक union
प्रकार के लिए एक typedef
का उपयोग बहुत समान है।
typedef union Float Float;
union Float
{
float f;
char b[sizeof(float)];
};
इसके समान एक संरचना का उपयोग बाइट्स का विश्लेषण करने के लिए किया जा सकता है जो float
मूल्य बनाते हैं।
टंकण की सरल उपयोग
डेटा प्रकार के लिए संक्षिप्त नाम देने के लिए
के बजाय:
long long int foo;
struct mystructure object;
एक का उपयोग कर सकते हैं
/* write once */
typedef long long ll;
typedef struct mystructure mystruct;
/* use whenever needed */
ll foo;
mystruct object;
यह टाइपिंग की मात्रा को कम करता है यदि प्रोग्राम में कई बार टाइप का उपयोग किया जाता है।
पोर्टेबिलिटी में सुधार
डेटा प्रकारों की विशेषताएँ विभिन्न आर्किटेक्चर में भिन्न होती हैं। उदाहरण के लिए, int
एक कार्यान्वयन में 2-बाइट प्रकार और दूसरे में 4-बाइट प्रकार हो सकता है। मान लीजिए कि एक प्रोग्राम को सही ढंग से चलाने के लिए 4-बाइट प्रकार का उपयोग करने की आवश्यकता है।
एक क्रियान्वयन में, int
का आकार 2 बाइट्स और long
4 बाइट्स का होना चाहिए। दूसरे में, int
का आकार 4 बाइट्स है और वह long
8 बाइट्स है। यदि कार्यक्रम दूसरे कार्यान्वयन का उपयोग करते हुए लिखा गया है,
/* program expecting a 4 byte integer */
int foo; /* need to hold 4 bytes to work */
/* some code involving many more ints */
कार्यक्रम को पहले कार्यान्वयन में चलाने के लिए, सभी int
घोषणाओं को long
बदलना होगा।
/* program now needs long */
long foo; /*need to hold 4 bytes to work */
/* some code involving many more longs - lot to be changed */
इससे बचने के लिए, कोई व्यक्ति typedef
उपयोग कर सकता है
/* program expecting a 4 byte integer */
typedef int myint; /* need to declare once - only one line to modify if needed */
myint foo; /* need to hold 4 bytes to work */
/* some code involving many more myints */
फिर, पूरे कार्यक्रम की जांच करने के बजाय, केवल typedef
कथन को हर बार बदलना होगा।
<stdint.h>
शीर्षक और संबंधित <inttypes.h>
हैडर परिभाषित मानक प्रकार नाम (का उपयोग कर typedef
विभिन्न आकार के पूर्णांकों, और इन नामों के लिए) अक्सर आधुनिक कोड है कि जरूरतों को तय आकार पूर्णांकों में सबसे अच्छा विकल्प है। उदाहरण के लिए, uint8_t
एक अहस्ताक्षरित 8-बिट पूर्णांक प्रकार है; int64_t
एक हस्ताक्षरित 64-बिट पूर्णांक प्रकार है। प्रकार uintptr_t
एक अहस्ताक्षरित पूर्णांक प्रकार है जो किसी भी सूचक को ऑब्जेक्ट पर रखने के लिए पर्याप्त है। ये प्रकार सैद्धांतिक रूप से वैकल्पिक हैं - लेकिन उनके लिए उपलब्ध नहीं होना दुर्लभ है। uint_least16_t
(कम से कम 16 बिट्स के साथ सबसे छोटा अहस्ताक्षरित पूर्णांक प्रकार) और int_fast32_t
(कम से कम 32 बिट्स के साथ सबसे तेज़ हस्ताक्षरित पूर्णांक प्रकार) जैसे वेरिएंट हैं। इसके अलावा, intmax_t
और uintmax_t
कार्यान्वयन द्वारा समर्थित सबसे बड़े पूर्णांक प्रकार हैं। ये प्रकार अनिवार्य हैं।
उपयोग निर्दिष्ट करना या पठनीयता में सुधार करना
यदि डेटा के एक सेट का एक विशेष उद्देश्य है, तो कोई इसे एक सार्थक नाम देने के लिए typedef
का उपयोग कर सकता है। इसके अलावा, यदि डेटा की संपत्ति ऐसी बदल जाती है कि आधार प्रकार को बदलना होगा, तो पूरे प्रोग्राम की जांच करने के बजाय केवल typedef
कथन को बदलना होगा।
फंक्शन पॉइंटर्स के लिए टाइप्डिफ
हम फ़ंक्शन पॉइंटर्स के उपयोग को सरल बनाने के लिए typedef
का उपयोग कर सकते हैं। कल्पना करें कि हमारे कुछ कार्य हैं, सभी में एक ही हस्ताक्षर हैं, जो विभिन्न तरीकों से कुछ का प्रिंट आउट करने के लिए अपने तर्क का उपयोग करते हैं:
#include<stdio.h>
void print_to_n(int n)
{
for (int i = 1; i <= n; ++i)
printf("%d\n", i);
}
void print_n(int n)
{
printf("%d\n, n);
}
अब हम एक typedef
का उपयोग करके नामांकित फ़ंक्शन पॉइंटर टाइप प्रिंटर बना सकते हैं:
typedef void (*printer_t)(int);
यह एक प्रकार, नामित बनाता printer_t
एक समारोह है कि एक ही ले जाता है के लिए सूचक के लिए int
तर्क और रिटर्न कुछ भी नहीं है, जो काम करता है हम ऊपर है के हस्ताक्षर से मेल खाता है। इसका उपयोग करने के लिए हम बनाए गए प्रकार का एक वैरिएबल बनाते हैं और इसे एक प्रश्न में दिए गए कार्यों के लिए एक पॉइंटर असाइन करते हैं:
printer_t p = &print_to_n;
void (*p)(int) = &print_to_n; // This would be required without the type
फिर फ़ंक्शन पॉइंटर चर द्वारा इंगित फ़ंक्शन को कॉल करने के लिए:
p(5); // Prints 1 2 3 4 5 on separate lines
(*p)(5); // So does this
इस प्रकार typedef
फ़ंक्शन पॉइंटर्स के साथ काम करते समय सरल सिंटैक्स की अनुमति देता है। यह तब और अधिक स्पष्ट हो जाता है जब फ़ंक्शन पॉइंटर्स का उपयोग अधिक जटिल स्थितियों में किया जाता है, जैसे कि कार्यों के लिए तर्क।
यदि आप एक फ़ंक्शन पॉइंटर का उपयोग कर रहे हैं, जो बिना फ़ंक्शन पॉइंटर के पैरामीटर के रूप में फ़ंक्शन पॉइंटर को परिभाषित करता है, तो फ़ंक्शन परिभाषा होगी।
void foo (void (*printer)(int), int y){
//code
printer(y);
//code
}
हालाँकि, यह typedef
साथ है:
void foo (printer_t printer, int y){
//code
printer(y);
//code
}
इसी तरह फ़ंक्शन फ़ंक्शन पॉइंटर्स को वापस कर सकते हैं और फिर से, ऐसा करते समय typedef
का उपयोग वाक्यविन्यास को सरल बना सकता है।
एक क्लासिक उदाहरण <signal.h>
से signal
फ़ंक्शन है। इसके लिए घोषणा (सी मानक से) है:
void (*signal(int sig, void (*func)(int)))(int);
यह एक ऐसा फंक्शन है जो दो तर्कों को लेता है - एक int
और एक फंक्शन के लिए एक पॉइंटर जो एक आर्ग्युमेंट को एक int
रूप में लेता है और कुछ भी नहीं लौटाता है - और जो एक पॉइंटर को दूसरे लॉजिक की तरह काम करने के लिए लौटाता है।
यदि हमने पॉइंटर प्रकार के कार्य के लिए SigCatcher
को एक उपनाम के रूप में परिभाषित किया है:
typedef void (*SigCatcher)(int);
तब हम signal()
का उपयोग करके घोषणा कर सकते थे:
SigCatcher signal(int sig, SigCatcher func);
कुल मिलाकर, यह समझना आसान है (भले ही सी मानक ने काम करने के लिए एक प्रकार को परिभाषित करने के लिए चुना नहीं था)। signal
समारोह दो तर्क, एक लेता है int
और एक SigCatcher
, और यह एक रिटर्न SigCatcher
- जहां एक SigCatcher
एक समारोह है कि एक लेता है के लिए सूचक है int
तर्क और रिटर्न कुछ भी नहीं।
यद्यपि फ़ंक्शन प्रकारों के लिए सूचक के लिए typedef
नामों का उपयोग करना जीवन को आसान बनाता है, यह उन लोगों के लिए भी भ्रम पैदा कर सकता है जो बाद में आपके कोड को बनाए रखेंगे, इसलिए सावधानी और उचित प्रलेखन के साथ उपयोग करें। फ़ंक्शन पॉइंटर्स भी देखें।