क्या चर चौड़ाई के प्रकारों को आधुनिक C में निश्चित प्रकारों द्वारा प्रतिस्थापित किया गया है?


21

कोड रिव्यू पर समीक्षा में आज मुझे एक दिलचस्प बात समझ में आई । @Veedrac ने इस उत्तर में सिफारिश की है कि चर आकार के प्रकार (जैसे intऔर long) को निश्चित आकार के प्रकार uint64_tऔर जैसे से प्रतिस्थापित किया जाना चाहिए uint32_t। उस उत्तर की टिप्पणियों से उद्धरण:

Int और long के आकार (और इस प्रकार वे जो मान रख सकते हैं) प्लेटफ़ॉर्म-निर्भर हैं। दूसरी ओर, int32_t हमेशा 32 बिट लंबा होता है। Int का उपयोग करने का मतलब है कि आपका कोड अलग-अलग प्लेटफ़ॉर्म पर अलग-अलग तरीके से काम करता है, जो आम तौर पर वह नहीं होता जो आप चाहते हैं।

सामान्य प्रकारों को ठीक नहीं करने के मानक के पीछे तर्क आंशिक रूप से यहाँ @supercat द्वारा समझाया गया है। सी को आर्किटेक्चर में पोर्टेबल होना लिखा गया था, विधानसभा के विपरीत जो उस समय सिस्टम प्रोग्रामिंग के लिए आमतौर पर उपयोग किया जाता था।

मुझे लगता है कि डिजाइन का उद्देश्य मूल रूप से यह था कि इंट के अलावा अन्य प्रकार सबसे छोटी चीज हो सकती है जो विभिन्न आकारों की संख्या को संभाल सकती है, और यह इंट सबसे व्यावहारिक "सामान्य-उद्देश्य" आकार हो सकता है जो +/- 32767 को संभाल सकता है।

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

क्या मैं 70 के दशक में फंस गया हूं या वास्तव intमें C99 और उससे आगे के युग में उपयोग करने का औचित्य है?


1
लोगों का एक हिस्सा सिर्फ दूसरों की नकल करता है। मेरा मानना ​​है कि अधिकांश कोड फिक्स्ड-बिट-प्रकार को चेतनाशून्य कर दिया गया था। न तो आकार निर्धारित करने का कोई कारण है और न ही करने का। मेरे पास मुख्य रूप से 16 बिट प्लेटफ़ॉर्म (80 के दशक के एमएस-डॉस और एक्सनिक्स) पर बना कोड है, जो कि बस किसी भी 64 पर संकलित करता है और चलाता है और नए शब्द-आकार और पते के फायदे, बस इसे संकलित करता है। कहने का तात्पर्य यह है कि डेटा को निर्यात / आयात करने के लिए क्रमबद्धता इसे पोर्टेबल रखने के लिए एक बहुत ही महत्वपूर्ण वास्तुकला डिजाइन है।
लुसियानो

जवाबों:


7

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

उदाहरण के लिए विचार करें:

uint32_t upow(uint32_t n, uint32_t exponent)
{
  while(exponent--)
    n*=n;
  return n;
}

int32_t spow(int32_t n, uint32_t exponent)
{
  while(exponent--)
    n*=n;
  return n;
}

मशीनों जहां पर intया तो 4294967295 रोक नहीं सकते, या 18446744065119617025 धारण कर सकते हैं, पहले समारोह के सभी मानों के लिए परिभाषित किया जाएगा nऔर exponent, और अपने व्यवहार के आकार से प्रभावित नहीं होगा int; आगे, मानक की जरूरत नहीं होगी कि यह किसी भी आकार के साथ मशीनों पर अलग व्यवहार उपज int में से कुछ मूल्यों nऔर exponent, के रूप में एक तथापि, यह कारण मशीनों पर अपरिभाषित व्यवहार जहां 4294967295 प्रदर्शनीय है आह्वान करने के लिए होगा intलेकिन 18446744065119617025 नहीं है।

दूसरा समारोह के कुछ मूल्यों के लिए अपरिभाषित व्यवहार निकलेगा nऔर exponentमशीनों जहां पर int4611686014132420609 धारण नहीं कर सकता है, लेकिन के सभी मानों के लिए परिभाषित व्यवहार निकलेगा nऔर exponentसभी मशीनों पर जहां यह (विनिर्देशों के लिए कर सकते हैं int32_tमतलब है कि two's-पूरक मशीनों जहां उस पर रैपिंग व्यवहार से छोटा है int)।

ऐतिहासिक रूप से, भले ही मानक ने कहा कि कंपाइलरों को intओवरफ्लो में क्या करना चाहिए, इसके बारे में कुछ भी नहीं है upow, कंपाइलरों ने लगातार उसी व्यवहार का उत्पादन किया होगा जैसे कि intओवरफ्लो करने के लिए पर्याप्त नहीं था। दुर्भाग्य से, कुछ नए संकलक मानक द्वारा अनिवार्य नहीं किए गए व्यवहार को समाप्त करके "अनुकूलन" कार्यक्रमों की तलाश कर सकते हैं।


3
कोई भी व्यक्ति मैन्युअल रूप से लागू करना चाहता है pow, याद रखें कि यह कोड केवल एक उदाहरण है और इसे पूरा नहीं करता है exponent=0!
मार्क हर्ड

1
मुझे लगता है कि आपको उपसर्ग घटने वाले ऑपरेटर का उपयोग करना चाहिए था, उपसर्ग नहीं, वर्तमान में यह 1 अतिरिक्त गुणन कर रहा है। उदाहरण के लिए exponent=1, परिणाम में एक बार स्वयं गुणा किया जाएगा, क्योंकि चेक के बाद वेतन वृद्धि का प्रदर्शन किया जाता है, अर्थात - एक्सप्रेशनर), कोई गुणन नहीं किया जाएगा और n को ही वापस कर दिया जाएगा।
ALXGTV

2
@MarkHurd: फ़ंक्शन को खराब रूप से नामित किया गया है, क्योंकि यह वास्तव में गणना करता है N^(2^exponent), लेकिन प्रपत्र की गणना N^(2^exponent)अक्सर घातांक कार्यों की गणना में उपयोग की जाती है, और mod-4294967296 घातांक चीजों के लिए उपयोगी है जैसे कि दो तारों के संघटन के हैश की गणना करना हैश ज्ञात हैं।
सुपरकैट

1
@ALXGTV: इस फंक्शन का मतलब कुछ ऐसी चीजों से जुड़ा होना था, जो शक्ति से संबंधित हो। जो वास्तव में गणना करता है वह N ^ (2 ^ घातांक) है, जो कुशलता से N ^ घातांक की गणना का एक हिस्सा है, और अच्छी तरह से विफल हो सकता है भले ही N छोटा हो (बार-बार uint32_t31 से गुणा करना कभी भी UB नहीं होगा, लेकिन कुशल 31 ^ N की गणना करने का तरीका 31 ^ (2 ^ N) की गणना करता है, जो होगा।
13

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

4

संकेत से संबंधित मानों के लिए (और इस प्रकार, पता योग्य मेमोरी की मात्रा के लिए) जैसे बफर आकार, सरणी अनुक्रमित, और विंडोज ' lParam, यह आर्किटेक्चर-निर्भर आकार के साथ पूर्णांक प्रकार के होने के लिए समझ में आता है। तो, चर-आकार प्रकार अभी भी उपयोगी हैं। यही कारण है कि हम typedefs है size_t, ptrdiff_t, intptr_t, आदि वे राशि की जरूरत है क्योंकि निर्मित सी प्रकार पूर्णांक में से कोई भी सूचक आकार हो typedefs किया जाना है।

तो सवाल यह है कि क्या वास्तव में char, short, int, long, और long longअभी भी उपयोगी होते हैं।

IME, intअधिकांश चीजों के लिए C और C ++ प्रोग्राम का उपयोग करना अभी भी सामान्य है । और अधिकांश समय (यानी, जब आपके नंबर and 32 767 की सीमा में हों और आपके पास कठोर प्रदर्शन आवश्यकताएं नहीं हैं), यह ठीक काम करता है।

लेकिन क्या होगा यदि आपको 17-32 बिट रेंज (बड़े शहरों की आबादी की तरह) में संख्याओं के साथ काम करने की आवश्यकता है? आप उपयोग कर सकते हैं int, लेकिन यह एक प्लेटफ़ॉर्म निर्भरता पर हार्ड-कोडिंग होगा। यदि आप मानक का सख्ती से पालन करना चाहते हैं, तो आप उपयोग कर सकते हैं long, जो कम से कम 32 बिट्स होने की गारंटी है।

समस्या यह है कि सी मानक पूर्णांक प्रकार के लिए कोई अधिकतम आकार निर्दिष्ट नहीं करता है । ऐसे कार्यान्वयन हैं जिन longपर 64 बिट्स हैं, जो आपके मेमोरी उपयोग को दोगुना कर देते हैं। और अगर ये longलाखों के आइटम के साथ एक सरणी के तत्व होते हैं, तो आप पागल की तरह स्मृति को फेंक देंगे।

तो, न तो intहै और न ही longएक उपयुक्त प्रकार यहाँ उपयोग करने के लिए यदि आप अपने कार्यक्रम दोनों पार मंच और स्मृति कुशल होना चाहते है। दर्ज करें int_least32_t

  • आपका I16L32 कंपाइलर आपको 32-बिट देता है long, जिससे होने वाली परेशानियों से बचा जा सकता हैint
  • आपका I32L64 कंपाइलर आपको 32-बिट देता है int, 64-बिट की व्यर्थ मेमोरी से बचता है long
  • आपका I36L72 कंपाइलर आपको 36-बिट देता है int

OTOH, मान लें कि आपको बड़ी संख्या या विशाल सरणियों की आवश्यकता नहीं है , लेकिन आपको गति की आवश्यकता है। और intसभी प्लेटफार्मों पर काफी बड़ा हो सकता है, लेकिन जरूरी नहीं कि यह सबसे तेज प्रकार हो: 64-बिट सिस्टम में आमतौर पर अभी भी 32-बिट है int। लेकिन आप उपयोग कर सकते हैं int_fast16_tऔर "सबसे तेज" प्रकार मिलता है, यह है कि क्या int, longया long long

तो, वहाँ से प्रकार के लिए व्यावहारिक उपयोग के मामले हैं <stdint.h>। मानक पूर्णांक प्रकारों का कोई मतलब नहीं है। विशेष रूप से long, जो कि 32 या 64 बिट्स हो सकता है, और कंपाइलर लेखकों की सनक के आधार पर, एक पॉइंटर को पकड़ने के लिए काफी बड़ा हो सकता है या नहीं भी हो सकता है।


जैसे प्रकार के साथ एक समस्या uint_least32_tयह है कि अन्य प्रकारों के साथ उनकी बातचीत भी उन लोगों की तुलना में अधिक कमजोर रूप से निर्दिष्ट है uint32_t। IMHO, मानक को प्रकारों को परिभाषित करना चाहिए uwrap32_tऔर unum32_t, शब्दार्थ के साथ कि किसी भी संकलक जो प्रकार को परिभाषित करता है uwrap32_t, को एक अहस्ताक्षरित प्रकार के रूप में प्रचारित करना चाहिए अनिवार्य रूप से समान मामलों में इसे बढ़ावा दिया जाएगा यदि int32 बिट्स थे, और कोई भी संकलक जो परिभाषित करता है प्रकार unum32_tसुनिश्चित करता है कि बुनियादी अंकगणितीय प्रचार हमेशा इसे एक हस्ताक्षरित प्रकार में परिवर्तित करते हैं जो इसका मूल्य रखने में सक्षम है।
सुपरकैट

साथ ही, मानक भी प्रकार जिसका भंडारण और अलियासिंग के साथ संगत कर रहे थे निर्धारित कर सकते हैं intN_tऔर uintN_t, और जिसका परिभाषित व्यवहार किया जाएगा संगत के साथ intN_tऔर uintN_tहै, लेकिन जो compilers अपनी सीमा के बाहर मूल्यों सौंपा मामले कोड में कुछ स्वतंत्रता प्रदान करेगा [अनुमति देता है उन है कि थे के समान अर्थ विज्ञान शायद के लिए इरादा है uint_least32_t, लेकिन अनिश्चितता के बिना जैसे कि एक जोड़ने uint_least16_tऔर int32_tएक हस्ताक्षरित या usnigned परिणाम होगा।
सुपरकैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.