क्या मुझे C # में अहस्ताक्षरित int का उपयोग करने से बचना चाहिए?


23

मैंने हाल ही में C # में अहस्ताक्षरित पूर्णांक के उपयोग के बारे में सोचा था (और मुझे लगता है कि इसी तरह के तर्क को अन्य "उच्च स्तरीय भाषाओं" के बारे में कहा जा सकता है)

जब एक पूर्णांक की आवश्यकता होती है, तो मुझे आम तौर पर पूर्णांक के आकार की दुविधा का सामना नहीं करना पड़ता है, एक उदाहरण एक व्यक्ति वर्ग की आयु संपत्ति होगा (लेकिन प्रश्न गुणों तक सीमित नहीं है)। इस बात को ध्यान में रखते हुए कि जहाँ तक मैं देख सकता हूँ, एक हस्ताक्षरित पूर्णांक ("int") - पठनीयता पर एक अहस्ताक्षरित पूर्णांक ("uint") का उपयोग करने का केवल एक फायदा है। यदि मैं इस विचार को व्यक्त करना चाहता हूं कि एक आयु केवल सकारात्मक हो सकती है तो मैं इसे आयु प्रकार को निर्धारित करके इसे प्राप्त कर सकता हूं।

दूसरी ओर, अहस्ताक्षरित पूर्णांकों पर गणना से सभी प्रकार की त्रुटियां हो सकती हैं और इससे दो युगों को घटाते हुए संचालन करना कठिन हो जाता है। (मैंने पढ़ा है कि यह उन कारणों में से एक है जो जावा ने अहस्ताक्षरित पूर्णांक छोड़ दिया है)

सी # के मामले में मैं यह भी सोच सकता हूं कि सेटर पर एक गार्ड क्लॉज एक ऐसा समाधान होगा जो दो दुनियाओं में से सबसे अच्छा देता है, लेकिन, यह तब लागू नहीं होगा जब मैं उदाहरण के लिए, एक उम्र किसी विधि से गुजरती होगी। वर्कअराउंड एज नामक क्लास को डिफाइन करना होगा और प्रॉपर्टी की उम्र एक ही चीज होगी, लेकिन इस पैटर्न से मुझे कई क्लास मिलेंगे और कन्फ्यूजन का स्रोत होगा (अन्य डेवलपर्स को तब पता नहीं चलेगा जब ऑब्जेक्ट सिर्फ एक रैपर होगा और जब यह कुछ अधिक नरम है)।

इस मुद्दे के बारे में कुछ सामान्य सर्वोत्तम अभ्यास क्या हैं? मुझे इस प्रकार के परिदृश्य से कैसे निपटना चाहिए?



1
इसके अतिरिक्त अहस्ताक्षरित int सीएलएस अनुरूप नहीं है, जिसका अर्थ है कि आप एपीआई को कॉल नहीं कर सकते हैं जो उन्हें अन्य .NET भाषाओं से उपयोग करते हैं।
नाथन कूपर

2
@NathanCooper: ... "एपीआई को कॉल नहीं कर सकते जो उन्हें कुछ अन्य भाषाओं से उपयोग करते हैं"। उनके लिए मेटाडेटा मानकीकृत है, इसलिए सभी .NET भाषाएँ जो अहस्ताक्षरित प्रकारों का समर्थन करती हैं, बस ठीक-ठाक चलेंगी।
बेन वोइगट

5
आपके विशिष्ट उदाहरण को संबोधित करने के लिए, मेरे पास पहले स्थान पर आयु नामक संपत्ति नहीं होगी। मेरे पास बर्थडे या क्रिएशनटाइम या जो कुछ भी है, उसके पास एक संपत्ति होगी और उसमें से उम्र की गणना करें।
एरिक लिपर्ट

2
"... लेकिन इस पैटर्न से मुझे कई कक्षाएं मिलेंगी और भ्रम की स्थिति पैदा होगी" वास्तव में यही सही है। बस कुख्यात आदिम जुनून विरोधी पैटर्न के लिए खोज ।
सांगो

जवाबों:


24

.NET फ्रेमवर्क के डिजाइनरों ने कई कारणों से 32 बिट हस्ताक्षरित पूर्णांक को "सामान्य-उद्देश्य संख्या" के रूप में चुना:

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

अहस्ताक्षरित ints का उपयोग करने का कारण पठनीयता नहीं है; यह गणित को प्राप्त करने की क्षमता रखता है जो केवल एक अहस्ताक्षरित int प्रदान करता है।

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


2
अच्छा जवाब! इसके अलावा कुछ ऐसे मामले भी हो सकते हैं जहां एक अहस्ताक्षरित int वास्तव में अनजाने में अधिक त्रुटियां उत्पन्न कर सकता है (हालांकि शायद लोग तुरंत स्पॉट किए जाते हैं, लेकिन थोड़ा भ्रमित होते हैं) - एक अहस्ताक्षरित int काउंटर के साथ रिवर्स में लूपिंग की कल्पना करें क्योंकि कुछ आकार पूर्णांक है: for (uint j=some_size-1; j >= 0; --j)- वूप्स सुनिश्चित नहीं है कि यह C # में एक मुद्दा है)! मुझे यह मुद्दा कोड में मिला, जिसके पहले से संभव के रूप में C साइड पर अहस्ताक्षरित int का उपयोग करने की कोशिश की गई - और हमने इसे intबाद में केवल पक्ष में बदलने के लिए समाप्त कर दिया, और कम संकलक चेतावनियों के साथ हमारा जीवन बहुत आसान था।

14
"शायद ही कभी शून्य और 2 ^ 32-1 के बीच एक संख्या के लिए एक वास्तविक दुनिया संख्यात्मक सीमा होती है।" मेरे अनुभव में, यदि आपको 2 ^ 31 से बड़ी संख्या की आवश्यकता है, तो आपको बहुत अधिक संख्या में 2 ^ 32 से बड़ी संख्याओं की आवश्यकता होगी, इसलिए आप बस (हस्ताक्षरित) int64 पर जा सकते हैं वह बात।
मेसन व्हीलर

3
@Panzercrisis: यह थोड़ा गंभीर है। यह कहना अधिक सटीक होगा कि " intअधिकांश समय का उपयोग करें क्योंकि यह स्थापित सम्मेलन है, और यह वही है जो अधिकांश लोग नियमित रूप से उपयोग किए जाने की उम्मीद करने जा रहे हैं। uintजब आपको विशेष कैपबिलिटीज़ की आवश्यकता होती है तो उपयोग करें uint।" याद रखें, फ्रेमवर्क डिजाइनरों ने इस सम्मेलन का बड़े पैमाने पर पालन करने का फैसला किया, इसलिए आप uintकई फ्रेमवर्क संदर्भों में भी इसका उपयोग नहीं कर सकते (यह टाइप-संगत नहीं है)।
रॉबर्ट हार्वे

2
@Panzercrisis यह एक अत्यधिक मजबूत फोंटसिंग हो सकता है; लेकिन मुझे यकीन नहीं है कि अगर मैंने कभी भी C # में अहस्ताक्षरित प्रकार का उपयोग नहीं किया है, सिवाय इसके कि जब मैं win32 एपिस (जहां सम्मेलन यह है कि कॉन्स्टेंट / झंडे / आदि अहस्ताक्षरित हैं) को कॉल कर रहा है।
दान नीली

4
यह वास्तव में काफी दुर्लभ है। केवल एक बार जब मैं अहस्ताक्षरित ints का उपयोग करता हूं, तो बिट-ट्विडलिंग परिदृश्यों में होता है।
रॉबर्ट हार्वे

8

आम तौर पर, आपको हमेशा अपने डेटा के लिए सबसे विशिष्ट डेटा प्रकार का उपयोग करना चाहिए।

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

C # में इसके साथ दो समस्याएं हैं।
सबसे पहले, अधिकांश सी # डेवलपर्स intपूरे नंबर का प्रतिनिधित्व करने के लिए (जब तक उपयोग करने का कोई कारण नहीं है long) का उपयोग करते हैं । इसका मतलब है कि अन्य डेवलपर्स डेटा प्रकार की जांच करने के लिए नहीं सोचेंगे, इसलिए उन्हें ऊपर उल्लिखित त्रुटियां मिलेंगी। दूसरा, और अधिक महत्वपूर्ण मुद्दा है, / था कि नेट के मूल अंकगणितीय ऑपरेटर केवल समर्थित int, uint, long, ulong, float, डबल, और decimal*। यह आज भी मामला है ( सी # 5.0 भाषा कल्पना में खंड 7.8.4 देखें )। आप निम्न कोड का उपयोग करके स्वयं इसका परीक्षण कर सकते हैं:

byte a, b;
a = 1;
b = 2;
var c = a - b;      //In visual studio, hover over "var" and the tip will indicate the data type, or you can get the value from cName below.
string cName = c.GetType().Namespace + '.' + c.GetType().Name;

हमारे byte- byteका परिणाम एक int( System.Int32) है।

इन दो मुद्दों ने "केवल संपूर्ण संख्याओं के लिए int का उपयोग करें" अभ्यास को जन्म दिया, जो इतना आम है।

तो अपने प्रश्न का उत्तर देने के लिए, C # में आमतौर पर एक अच्छा विचार है intजब तक कि आप छड़ी न करें:

  • एक स्वचालित कोड जनरेटर ने एक अलग मूल्य (जैसे एंटिटी फ्रेमवर्क) का उपयोग किया।
  • परियोजना के अन्य सभी डेवलपर्स इस बात से अवगत हैं कि आप कम सामान्य डेटा प्रकारों का उपयोग कर रहे हैं (इसमें एक टिप्पणी इंगित करता है कि आपने डेटा प्रकार और क्यों उपयोग किया है)।
  • कम आम डेटा प्रकार आमतौर पर परियोजना में पहले से ही उपयोग किए जाते हैं।
  • कार्यक्रम कम आम डेटा प्रकार के लाभों की आवश्यकता है (यदि आप इन आप रैम में रखने की जरूरत 100 मिलियन है, तो एक के बीच का अंतर byteऔर एक intया एक intऔर एक longमहत्वपूर्ण है, या अहस्ताक्षरित की अंकगणित मतभेद पहले ही उल्लेख किया)।

यदि आपको डेटा पर गणित करने की आवश्यकता है, तो सामान्य प्रकारों से चिपके रहें।
याद रखें, आप एक प्रकार से दूसरे में डाल सकते हैं। यह सीपीयू स्टैंड बिंदु से कम कुशल हो सकता है, इसलिए आप शायद 7 सामान्य प्रकारों में से एक के साथ बेहतर हैं, लेकिन यदि आवश्यक हो तो यह एक विकल्प है।

Enumerations ( enum) उपरोक्त दिशानिर्देशों में से एक मेरा व्यक्तिगत अपवाद है। यदि मेरे पास कुछ ही विकल्प हैं, तो मैं enum को बाइट या शॉर्ट बनाने के लिए निर्दिष्ट करूँगा । यदि मुझे ध्वजांकित एनम में अंतिम बिट की आवश्यकता है, uintतो मैं इस प्रकार को निर्दिष्ट करूंगा ताकि मैं ध्वज के लिए मान सेट करने के लिए हेक्स का उपयोग कर सकूं।

यदि आप किसी संपत्ति का उपयोग मूल्य प्रतिबंधक कोड के साथ करते हैं, तो सारांश टैग में स्पष्ट करना सुनिश्चित करें कि क्या प्रतिबंध हैं और क्यों।

* C # उपनाम का उपयोग .NET नाम के बजाय किया जाता है System.Int32क्योंकि यह C # प्रश्न है।

नोट: .NET डेवलपर्स (जो मुझे नहीं मिल सकता है) से एक ब्लॉग या लेख था, जिसने अंकगणितीय कार्यों की सीमित संख्या और कुछ कारणों के बारे में बताया कि वे इसके बारे में चिंता क्यों नहीं करते थे। जैसा कि मुझे याद है, उन्होंने संकेत दिया कि उनके पास अन्य डेटा प्रकारों के लिए समर्थन जोड़ने की कोई योजना नहीं है।

नोट: जावा अहस्ताक्षरित डेटा प्रकारों का समर्थन नहीं करता है और पहले 8 या 16 बिट पूरे संख्याओं के लिए कोई समर्थन नहीं था। चूँकि कई C # डेवलपर्स जावा बैकग्राउंड से आए थे या दोनों भाषाओं में काम करने की जरूरत थी, इसलिए कभी-कभी एक भाषा की सीमाएं कृत्रिम रूप से दूसरे पर थोप दी जाती।


मेरे अंगूठे का सामान्य नियम है, "int का उपयोग, जब तक आप नहीं कर सकते"।
पेरीसी

@PerryC मेरा मानना ​​है कि यह सबसे आम सम्मेलन है। मेरे उत्तर का उद्देश्य एक अधिक संपूर्ण सम्मेलन प्रदान करना था जो आपको भाषा सुविधाओं का उपयोग करने की अनुमति देता है।
ट्रिस्पेड

6

आपको मुख्य रूप से दो चीजों से अवगत होना चाहिए: वह डेटा जिसका आप प्रतिनिधित्व कर रहे हैं, और आपकी गणना में कोई मध्यवर्ती चरण।

यह निश्चित रूप से समझ में आता है कि उम्र होना चाहिए unsigned int, क्योंकि हम आमतौर पर नकारात्मक उम्र पर विचार नहीं करते हैं। लेकिन फिर आप एक उम्र को दूसरे से घटाते हैं। यदि हम आँख बंद करके एक पूर्णांक को दूसरे से घटाते हैं, तो निश्चित रूप से एक नकारात्मक संख्या के साथ समाप्त होना संभव है, भले ही हम पहले सहमत हों कि नकारात्मक युगों का कोई मतलब नहीं है। तो इस मामले में आप चाहते हैं कि आपकी गणना एक हस्ताक्षरित पूर्णांक के साथ की जाए।

इस बारे में कि अहस्ताक्षरित मूल्य खराब हैं या नहीं, मैं कहूंगा कि अहस्ताक्षरित मूल्यों को बुरा कहना सामान्यीकरण है। जावा में अहस्ताक्षरित मूल्य नहीं हैं, जैसा कि आपने उल्लेख किया है, और यह लगातार मुझे परेशान करता है। A का byteमान 0-255 या 0x00-0xFF से हो सकता है। लेकिन यदि आप बाइट को 127 (0x7F) से बड़ा करना चाहते हैं, तो आपको या तो इसे एक ऋणात्मक संख्या के रूप में लिखना होगा या एक बाइट को पूर्णांक देना होगा। आप इस तरह दिखने वाले कोड को समाप्त करते हैं:

byte a = 0x80; // Won't compile!
byte b = (byte) 0x80;
byte c = -128; // Equal to b

ऊपर मुझे कोई अंत नहीं annoys। मुझे बाइट की अनुमति नहीं है, 197 का मूल्य है, भले ही बाइट्स से निपटने वाले अधिकांश समझदार लोगों के लिए यह पूरी तरह से वैध मूल्य है। मैं पूर्णांक डाल सकता हूं या मैं इस मामले में नकारात्मक मान (197 == -59) पा सकता हूं। इस पर भी विचार करें:

byte a = 70;
byte b = 80;
byte c = a + b; // c == -106

तो जैसा कि आप देख सकते हैं, वैध मूल्यों के साथ दो बाइट्स जोड़ना, और एक वैध मूल्य के साथ बाइट के साथ समाप्त होता है, साइन को बदलना समाप्त होता है। इतना ही नहीं बल्कि यह तुरंत स्पष्ट नहीं है कि 70 + 80 == -106। तकनीकी रूप से यह एक अतिप्रवाह है, लेकिन मेरे दिमाग में (एक इंसान के रूप में) एक बाइट 0xFF के तहत मूल्यों के लिए अतिप्रवाह नहीं होना चाहिए। जब मैं कागज पर बिट अंकगणित करता हूं, तो मैं 8 बिट को साइन बिट नहीं मानता हूं।

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

signed byte b = 0b10000000;
b = b >> 1; // b == 0b1100 0000
b = b & 0x7F;// b == 0b0100 0000

unsigned byte b = 0b10000000;
b = b >> 1; // b == 0b0100 0000;

यह सिर्फ अतिरिक्त कदम जोड़ता है जो मुझे लगता है कि आवश्यक नहीं होना चाहिए।

जबकि मैंने byteऊपर प्रयोग किया था , वही 32-बिट और 64-बिट पूर्णांक पर लागू होता है। unsignedअपंग नहीं होना और यह मुझे झकझोरता है कि जावा जैसी उच्च स्तरीय भाषाएं हैं जो उन्हें बिल्कुल भी अनुमति नहीं देती हैं। लेकिन ज्यादातर लोगों के लिए यह एक गैर-मुद्दा है, क्योंकि कई प्रोग्रामर बिट-स्तरीय अंकगणित से नहीं निपटते हैं।

अंत में, यदि आप उन्हें बिट्स के रूप में सोच रहे हैं, तो अहस्ताक्षरित पूर्णांक का उपयोग करना उपयोगी है, और जब आप उन्हें संख्या के रूप में सोच रहे हों, तो हस्ताक्षरित पूर्णांक का उपयोग करना उपयोगी होता है।


7
मैं अहस्ताक्षरित अभिन्न प्रकार (विशेष रूप से बाइट्स) के बिना भाषाओं के बारे में आपकी निराशा साझा करता हूं, लेकिन मुझे डर है कि यह यहां पूछे गए सवाल का सीधा जवाब नहीं है। हो सकता है कि आप एक निष्कर्ष जोड़ सकते हैं, जो मुझे लगता है, हो सकता है: "यदि आप संख्याओं के रूप में उनके बारे में सोच रहे हैं और यदि आप उनके बारे में संख्याओं के रूप में सोच रहे हैं, तो पूर्णांक पर हस्ताक्षर किए बिना पूर्णांकित पूर्णांक का उपयोग करें।"
5gon12eder

1
यह मैंने ऊपर टिप्पणी में कहा है। किसी और को उसी तरह सोचते देखकर खुशी हुई।
रोबर्ट ब्रिस्टो-जॉनसन 3
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.