हमें C में चर के डेटा प्रकार का उल्लेख क्यों करना है


19

आमतौर पर सी में, हमें कंप्यूटर को चर घोषणा में डेटा का प्रकार बताना होगा। निम्नलिखित कार्यक्रम में, मैं दो फ्लोटिंग पॉइंट संख्या X और Y का योग प्रिंट करना चाहता हूं।

#include<stdio.h>
main()
{
  float X=5.2;
  float Y=5.1;
  float Z;
  Z=Y+X;
  printf("%f",Z);

}

मुझे संकलक को चर X का प्रकार बताना था।

  • संकलक Xस्वयं के प्रकार का निर्धारण नहीं कर सकता है ?

हाँ, अगर मैं ऐसा कर सकता हूँ:

#define X 5.2

मैं अब अपने प्रोग्राम को कंपाइलर के प्रकार को बताए बिना लिख ​​सकता हूं X:

#include<stdio.h>
#define X 5.2
main()
{
  float Y=5.1;
  float Z;
  Z=Y+X;
  printf("%f",Z);

}  

इसलिए हम देखते हैं कि C भाषा में कुछ प्रकार की विशेषता है, जिसके उपयोग से यह अपने आप डेटा के प्रकार को निर्धारित कर सकता है। मेरे मामले में यह निर्धारित किया गया कि Xप्रकार फ्लोट का है।

  • जब हम मुख्य () में कुछ घोषित करते हैं तो हमें डेटा के प्रकार का उल्लेख क्यों करना पड़ता है? कंपाइलर डेटा चर का प्रकार अपने आप निर्धारित नहीं कर सकता main()क्योंकि यह अंदर होता है #define

14
वास्तव में वे दो कार्यक्रम समतुल्य नहीं हैं, ऐसे में वे थोड़ा अलग आउटपुट दे सकते हैं! 5.2एक है double, इसलिए पहला कार्यक्रम floatसटीक करने के लिए डबल शाब्दिक गोल करता है , फिर उन्हें फ़्लोट्स के रूप में जोड़ता है, जबकि दूसरा राउंड 5.1 का दोहरा प्रतिनिधित्व करता है doubleऔर इसे जोड़कर doubleमान 5.2 में doubleजोड़ देता है, फिरfloat सटीक करने के लिए उस गणना के परिणाम को गोल करता है। । क्योंकि गोलाई अलग-अलग जगहों पर होती है, इसलिए परिणाम कम हो सकता है। अन्यथा समान प्रोग्राम के व्यवहार को प्रभावित करने वाले चर के प्रकारों के लिए यह सिर्फ एक उदाहरण है।

12
जब आप करते हैं #define X 5.2, Xएक चर नहीं है, लेकिन एक स्थिर है, तो इसका शाब्दिक 5.2रूप से आपके द्वारा उल्लिखित कहीं भी पूर्वप्रक्रमक के रूप में प्रतिस्थापित किया जाता है X। आप पुन: असाइन नहीं कर सकते हैं X
स्क्रिप्ट

16
बस एक नोट के रूप में: यह एक आशीर्वाद और एक अभिशाप है। एक तरफ, आपको कुछ पात्रों को लिखना होगा, जब कंपाइलर वास्तव में आपके लिए कर सकता था (सी ++ का autoवास्तव में वही होता है जो आप चाहते हैं)। दूसरी ओर, यदि आपको लगता है कि आपको पता है कि आपका कोड क्या कर रहा है, और आपने वास्तव में कुछ और टाइप किया है, तो इस तरह का स्टैटिक टाइपिंग पहले एक त्रुटि पकड़ लेगा, इससे पहले कि यह एक बड़ी समस्या बन जाए। प्रत्येक भाषा एक संतुलन बनाती है: स्थैतिक टाइपिंग, टाइप इनफ़ॉर्मेंस, डायनेमिक टाइपिंग। कुछ कार्यों के लिए, अतिरिक्त टाइपिंग वास्तव में इसके लायक है। दूसरों के लिए, यह एक बेकार है।
Cort Ammon - मोनिका

Ocaml और / या हास्केल सीखें .... आप उनके प्रकार की अनुमान क्षमताओं के बारे में खुश होंगे।
बेसिल स्टारीनेवविच

जवाबों:


46

आप चर घोषणाओं की तुलना #defines से कर रहे हैं , जो गलत है। A के साथ #define, आप पहचानकर्ता और स्रोत कोड के स्निपेट के बीच एक मैपिंग बनाते हैं। सी प्रीप्रोसेसर तब वस्तुतः प्रदान किए गए स्निपेट के साथ उस पहचानकर्ता की किसी भी घटना को प्रतिस्थापित करेगा। लिख रहे हैं

#define FOO 40 + 2
int foos = FOO + FOO * FOO;

लेखन के रूप में संकलक के लिए एक ही बात समाप्त होता है

int foos = 40 + 2 + 40 + 2 * 40 + 2;

इसे स्वचालित प्रतिलिपि और पेस्ट के रूप में सोचें।

इसके अलावा, सामान्य चर को फिर से असाइन किया जा सकता है, जबकि एक मैक्रो के साथ बनाया #defineजा सकता है (हालांकि आप इसे फिर से कर सकते #defineहैं)। अभिव्यक्ति FOO = 7एक संकलक त्रुटि होगी, क्योंकि हम "rvalues" को निर्दिष्ट नहीं कर सकते: 40 + 2 = 7अवैध है।

तो, हमें सभी प्रकार की आवश्यकता क्यों है? कुछ भाषाएं स्पष्ट रूप से प्रकार से छुटकारा पाती हैं, यह विशेष रूप से स्क्रिप्टिंग भाषाओं में आम है। हालांकि, उनके पास आमतौर पर "डायनेमिक टाइपिंग" नाम की कोई चीज होती है, जहां चर के निश्चित प्रकार नहीं होते हैं, लेकिन मान होते हैं। हालांकि यह कहीं अधिक लचीला है, यह कम प्रदर्शन करने वाला भी है। C को प्रदर्शन पसंद है, इसलिए इसमें चर की एक बहुत ही सरल और कुशल अवधारणा है:

"स्टैक" नामक मेमोरी का खिंचाव होता है। प्रत्येक स्थानीय चर स्टैक पर एक क्षेत्र से मेल खाती है। अब सवाल यह है कि यह क्षेत्र कितने बाइट्स का है? सी में, प्रत्येक प्रकार में एक अच्छी तरह से परिभाषित आकार होता है जिसे आप क्वेरी कर सकते हैं sizeof(type)। कंपाइलर को प्रत्येक चर के प्रकार को जानने की आवश्यकता होती है ताकि वह स्टैक पर सही मात्रा में स्थान आरक्षित कर सके।

#defineएक निरंतर एनोटेशन की आवश्यकता वाले स्थिरांक क्यों नहीं बनाए जाते हैं? वे स्टैक पर संग्रहीत नहीं हैं। इसके बजाय, #defineप्रतिलिपि और पेस्ट की तुलना में स्रोत कोड के पुन: प्रयोज्य स्निपेट को थोड़ा अधिक बनाए रखने योग्य तरीके से बनाता है। जैसे स्रोत कोड में शाब्दिक "foo"या 42.87जिसके परिणामस्वरूप बाइनरी का एक अलग डेटा खंड में विशेष निर्देश के रूप में या तो इनलाइन संकलक द्वारा जमा हो जाती है, या।

हालाँकि, शाब्दिक प्रकार होते हैं। एक स्ट्रिंग शाब्दिक है char *42एक है, intलेकिन इसका उपयोग छोटे प्रकार (रूपांतरण को कम करने) के लिए भी किया जा सकता है। 42.8एक होगा double। आप एक शाब्दिक है और यह एक अलग प्रकार करना चाहते हैं (उदाहरण के लिए बनाने के लिए 42.8एक float, या 42एक unsigned long int), तो आप प्रत्यय उपयोग कर सकते हैं - शाब्दिक के बाद एक पत्र है कि परिवर्तन कैसे संकलक व्यवहार करता है कि शाब्दिक। हमारे मामले में, हम कह सकते हैं 42.8fया 42ul

कुछ भाषाओं में C की तरह स्थिर टाइपिंग है, लेकिन टाइप एनोटेशन वैकल्पिक हैं। उदाहरण एमएल, हास्केल, स्काला, सी #, सी ++ 11 और गो हैं। वह कैसे काम करता है? जादू? नहीं, इसे "प्रकार का अनुमान" कहा जाता है। सी # और गो में, संकलक एक असाइनमेंट के दाहिने हाथ की ओर देखता है, और उस प्रकार को घटाता है। यह काफी सीधा है अगर दाहिने हाथ की ओर एक शाब्दिक जैसे है 42ul। फिर यह स्पष्ट है कि चर का प्रकार क्या होना चाहिए। अन्य भाषाओं में अधिक जटिल एल्गोरिदम हैं जो इस बात को ध्यान में रखते हैं कि एक चर का उपयोग कैसे किया जाता है। जैसे यदि आप करते हैं x/2, तो xएक स्ट्रिंग नहीं हो सकता है लेकिन कुछ संख्यात्मक प्रकार होना चाहिए।


समझाने के लिए धन्यवाद। मुझे जो बात समझ में आती है वह यह है कि जब हम किसी वैरिएबल (स्थानीय या वैश्विक) के प्रकार की घोषणा करते हैं, तो हम वास्तव में कंपाइलर को बता रहे हैं कि स्टैक में उस वैरिएबल के लिए कितना स्थान आरक्षित होना चाहिए। दूसरी ओर #defineहम में एक स्थिरांक होता है जो सीधे बाइनरी कोड में परिवर्तित हो जाता है - हालाँकि जब तक यह हो सकता है - और यह मेमोरी में स्टोर हो जाता है जैसा कि यह है।
user106313

2
@ user31782 - काफी नहीं। जब आप एक चर की घोषणा करते हैं तो प्रकार कंपाइलर को बताता है कि चर में क्या गुण हैं। उन गुणों में से एक का आकार है; अन्य गुणों में यह शामिल है कि यह कैसे मूल्यों का प्रतिनिधित्व करता है और उन मूल्यों पर क्या संचालन किया जा सकता है।
पीट बेकर

@PeteBecker फिर कंपाइलर इन अन्य गुणों को कैसे जानता है #define X 5.2?
user106313

1
ऐसा इसलिए है क्योंकि गलत प्रकार से गुजरने से printfआपने अपरिभाषित व्यवहार का आह्वान किया है। मेरी मशीन पर जो स्निपेट हर बार एक अलग मूल्य प्रिंट करता है, आइडोन पर यह शून्य को प्रिंट करने के बाद क्रैश हो जाता है।
मट्टियो इटालिया

4
@ user31782 - "ऐसा लगता है कि मैं किसी भी डेटा प्रकार पर कोई भी ऑपरेशन कर सकता हूं" नहीं X*Yतो यह मान्य नहीं है Xऔर Yसंकेत हैं, लेकिन यह ठीक है अगर वे intएस हैं; *Xयदि मान्य नहीं है Xएक है int, लेकिन यह ठीक है अगर यह एक सूचक है।
पीट बेकर

4

दूसरे उदाहरण में X कभी फ्लोट नहीं है। इसे मैक्रो कहा जाता है, यह स्रोत में परिभाषित मैक्रो वैल्यू 'X' को वैल्यू के साथ बदल देता है। #Define पर एक पठनीय लेख यहाँ है

आपूर्ति कोड के मामले में, संकलन से पहले प्रीप्रोसेसर कोड को बदल देता है

Z=Y+X;

सेवा

Z=Y+5.2;

और जो संकलित हो जाता है।

इसका मतलब है कि आप उन 'मूल्यों' को भी बदल सकते हैं जैसे कोड

#define X sqrt(Y)

या और भी

#define X Y

3
इसे सिर्फ एक मैक्रो कहा जाता है, न कि वैरेडिक मैक्रो। एक वैरिएबल मैक्रो एक मैक्रो है जो एक चर संख्या में तर्क लेता है, जैसे #define FOO(...) { __VA_ARGS__ }
hvd

2
मेरा बुरा, ठीक हो जाएगा :)
जेम्स Snell

1

संक्षिप्त उत्तर C की जरूरत इतिहास के कारण / हार्डवेयर का प्रतिनिधित्व करने के लिए होती है।

इतिहास: सी 1970 के दशक में विकसित किया गया था और सिस्टम प्रोग्रामिंग के लिए एक भाषा के रूप में इरादा था। कोड आदर्श रूप से तेज है और हार्डवेयर की क्षमताओं का सबसे अच्छा उपयोग करता है।

संकलन के समय के प्रकारों का उल्लेख करना संभव हो गया होगा, लेकिन पहले से ही धीमा संकलन समय बढ़ गया होगा ( XKCD के 'संकलन' कार्टून का संदर्भ लें । यह C प्रकाशित होने के बाद कम से कम 10 वर्षों के लिए 'हैलो वर्ल्ड' पर लागू होता था )। रनटाइम के प्रकारों का उल्लेख करते हुए सिस्टम प्रोग्रामिंग के उद्देश्य को पूरा नहीं किया गया है। रनटाइम इनफ़ॉर्मेंस के लिए अतिरिक्त रन टाइम लाइब्रेरी की आवश्यकता होती है। सी पहले पीसी से बहुत पहले आया था। जिसमें 256 रैम थी। गीगाबाइट्स या मेगाबाइट्स नहीं बल्कि किलोबाइट्स।

अपने उदाहरण में, यदि आप प्रकारों को छोड़ देते हैं

   X=5.2;
   Y=5.1;

   Z=Y+X;

तब कंपाइलर खुशी से काम कर सकता था कि X & Y फ्लोट हैं और Z को समान बनाया। वास्तव में, एक आधुनिक संकलक भी काम करेगा कि X & Y की आवश्यकता नहीं है और बस Z को 10.3 पर सेट करें।

मान लें कि गणना किसी फ़ंक्शन के अंदर एम्बेडेड है। फ़ंक्शन लेखक हार्डवेयर के अपने ज्ञान का उपयोग करना चाहता है, या समस्या को हल किया जा सकता है।

क्या एक फ्लोट की तुलना में एक डबल उपयुक्त होगा? अधिक स्मृति लेता है और धीमी है, लेकिन परिणाम की सटीकता अधिक होगी।

हो सकता है कि फ़ंक्शन का रिटर्न मान इंट (या लंबा) हो सकता है क्योंकि दशमलव महत्वपूर्ण नहीं थे, हालांकि फ्लोट से इंट में रूपांतरण बिना लागत के नहीं है।

रिटर्न वैल्यू को भी डबल गारंटी दी जा सकती है कि फ्लोट + फ्लोट ओवरफ्लो नहीं करता है।

ये सभी प्रश्न आज लिखे गए अधिकांश विशाल कोड के लिए निरर्थक प्रतीत होते हैं, लेकिन जब C का उत्पादन किया गया था, तब ये महत्वपूर्ण थे।


1
यह स्पष्ट नहीं करता है कि प्रकार की घोषणाओं को वैकल्पिक क्यों नहीं बनाया गया है, प्रोग्रामर को या तो उन्हें स्पष्ट रूप से घोषित करने के लिए चुनने की अनुमति देता है या कंपाइलर पर भरोसा करने की अनुमति देता है
gnat

1
वास्तव में यह @gnat नहीं है। मैंने पाठ को ट्विक किया है लेकिन उस समय ऐसा करने का कोई मतलब नहीं था। डोमेन सी को वास्तव में 1 बाइट में 17, या 2 बाइट्स या 4 बाइट्स या एक स्ट्रिंग के रूप में या एक शब्द के भीतर 5 बिट्स के रूप में स्टोर करने का निर्णय लेने के लिए डिज़ाइन किया गया था।
itj

0

C में टाइप इंफ़ेक्शन नहीं है (यानी जब कंपाइलर आपके लिए वैरिएबल के प्रकार का अनुमान लगाता है तो इसे कहा जाता है) क्योंकि यह पुराना है। यह 1970 के दशक की शुरुआत में विकसित किया गया था

कई नई भाषाओं में ऐसी प्रणालियाँ हैं जो आपको उनके प्रकार (माणिक, जावास्क्रिप्ट, पाइथेट, आदि) को निर्दिष्ट किए बिना चर का उपयोग करने की अनुमति देती हैं।


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

2
जे एस नहीं है की अनुमति देते हैं आप के लिए छोड़ देते हैं प्रकार है - यह केवल आपके जो भी यह घोषणा करने के लिए अनुमति नहीं है है। यह गतिशील टाइपिंग, जहां मूल्यों प्रकार है (उदाहरण के लिए उपयोग करता trueहै boolean), नहीं चर (जैसे var xकिसी भी प्रकार का मान हो सकती है)। इसके अलावा, इस तरह के साधारण मामलों के लिए अनुमान लिखते ही सवाल से उन की गई है शायद एक दशक में जाना जाता है से पहले सी जारी किया गया था।
स्क्रिप्टिन

2
यह कथन गलत नहीं है (कुछ ऐसा करने के लिए आपको इसे अनुमति देने के लिए भी बाध्य करना चाहिए)। विद्यमान प्रकार का निष्कर्ष इस तथ्य को नहीं बदलता है कि C का प्रकार प्रणाली उसके ऐतिहासिक संदर्भ का परिणाम है (जैसा कि विशेष रूप से वर्णित दार्शनिक तर्क या तकनीकी सीमा के विपरीत)
Tristan Burnside

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

2
@BradS। फोरट्रान एक अच्छा उदाहरण नहीं है क्योंकि चर नाम का पहला अक्षर एक प्रकार की घोषणा है, जब तक कि आप implicit noneकिस मामले में उपयोग करते हैं, आपको एक प्रकार की घोषणा करनी चाहिए
डेमकी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.