आयाम, सूचकांक, आदि के लिए size_t या int


15

C ++ में, size_t(या, अधिक सही ढंग से T::size_typeजो "आमतौर पर" है size_t; यानी, एक unsignedप्रकार) का उपयोग रिटर्न मान के लिए size(), तर्क के लिए operator[]आदि के रूप में किया जाता है (देखें std::vector, एट अल।)।

दूसरी ओर, .NET भाषाएँ एक ही उद्देश्य के लिए int(और, वैकल्पिक रूप से long) का उपयोग करती हैं ; वास्तव में, सीएलएस-अनुपालन भाषाओं को अहस्ताक्षरित प्रकारों का समर्थन करने की आवश्यकता नहीं है

यह देखते हुए कि नेट सी से अधिक नया ++, कुछ मुझसे कहता है हो सकता है समस्याओं का उपयोग कर unsigned intभी चीजें हैं जो "संभवतः नहीं कर सकते" एक सरणी सूचकांक या लंबाई की तरह नकारात्मक हो लिए। क्या C ++ दृष्टिकोण "ऐतिहासिक विरूपण साक्ष्य" के लिए पश्चगामी संगतता है? या दो दृष्टिकोणों के बीच वास्तविक और महत्वपूर्ण डिज़ाइन ट्रेडऑफ़ हैं?

यह बात क्यों है? खैर ... मुझे C ++ में एक नए बहुआयामी वर्ग के लिए क्या उपयोग करना चाहिए; size_tयाint ?

struct Foo final // e.g., image, matrix, etc.
{
    typedef int32_t /* or int64_t*/ dimension_type; // *OR* always "size_t" ?
    typedef size_t size_type; // c.f., std::vector<>

    dimension_type bar_; // maybe rows, or x
    dimension_type baz_; // e.g., columns, or y

    size_type size() const { ... } // STL-like interface
};

6
वर्थ नोटिंग: .NET फ्रेमवर्क में कई स्थानों पर -1, "वापस नहीं मिला" या "सीमा के बाहर" इंगित करने के लिए, एक इंडेक्स लौटाने वाले फ़ंक्शंस से लौटाया जाता है। यह Compare()फ़ंक्शंस (कार्यान्वयन IComparable) से भी लौटा है । एक 32 बिट इंट को एक सामान्य संख्या के लिए टाइप करने के लिए जाना जाता है, जो मुझे उम्मीद है कि स्पष्ट कारण हैं।
रॉबर्ट हार्वे

जवाबों:


9

यह देखते हुए कि .NET C ++ से नया है, कुछ मुझे बताता है कि ऐसी चीजों के लिए भी अहस्ताक्षरित int का उपयोग करने में समस्याएँ हो सकती हैं, जो किसी सरणी इंडेक्स या लंबाई की तरह "संभवतः" नकारात्मक नहीं हो सकती हैं।

हाँ। कुछ प्रकार के अनुप्रयोगों जैसे छवि प्रसंस्करण या सरणी प्रसंस्करण के लिए, वर्तमान स्थिति के सापेक्ष तत्वों तक पहुंचना अक्सर आवश्यक होता है:

sum = data[k - 2] + data[k - 1] + data[k] + data[k + 1] + ...

इस प्रकार के अनुप्रयोगों में, आप बिना सोचे-समझे बिना अहस्ताक्षरित पूर्णांकों के साथ सीमा जाँच नहीं कर सकते:

if (k - 2 < 0) {
    throw std::out_of_range("will never be thrown"); 
}

if (k < 2) {
    throw std::out_of_range("will be thrown"); 
}

if (k < 2uL) {
    throw std::out_of_range("will be thrown, without signedness ambiguity"); 
}

इसके बजाय आपको पुनर्व्यवस्थित करना होगा अपनी सीमा जांच अभिव्यक्ति करना होगा। यही मुख्य अंतर है। प्रोग्रामर को पूर्णांक रूपांतरण नियमों को भी याद रखना चाहिए। जब संदेह हो, तो http://en.cppreference.com/w/cpp/language/operator_arithmetic#Conversions फिर से पढ़ें

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

C # वास्तव में उन अनुप्रयोगों के लिए डिज़ाइन किया गया है, जिन्हें प्रति सरणी 2 ^ 31 से अधिक तत्वों की आवश्यकता नहीं होगी। उदाहरण के लिए, एक स्प्रेडशीट एप्लिकेशन को कई पंक्तियों, स्तंभों या कोशिकाओं से निपटने की आवश्यकता नहीं है। C # वैकल्पिक जाँच अंकगणित होने से ऊपरी सीमा से संबंधित है संकलक विकल्पों के साथ खिलवाड़ किए बिना किसी कीवर्ड के साथ कोड के ब्लॉक के लिए सक्षम किया जा सकता है। इस कारण से, C # हस्ताक्षरित पूर्णांक के उपयोग का पक्षधर है। जब इन निर्णयों को पूरी तरह से माना जाता है, तो यह अच्छा समझ में आता है।

C ++ बस अलग है, और सही कोड प्राप्त करना कठिन है।

"कम से कम विस्मय के सिद्धांत" के संभावित उल्लंघन को हटाने के लिए हस्ताक्षरित अंकगणित को अनुमति देने के व्यावहारिक महत्व के संबंध में, एक मामला ओपनसीवी है, जो मैट्रिक्स तत्व सूचकांक, सरणी आकार, पिक्सेल चैनल गणना, आदि के लिए हस्ताक्षरित 32-बिट पूर्णांक का उपयोग करता है: छवि प्रोसेसिंग प्रोग्रामिंग डोमेन का एक उदाहरण है जो सापेक्ष सरणी सूचकांक का भारी उपयोग करता है। अहस्ताक्षरित पूर्णांक अंडरफ़्लो (नकारात्मक परिणाम चारों ओर लिपटा हुआ) एल्गोरिदम कार्यान्वयन को गंभीर रूप से जटिल करेगा।


ठीक यही स्थिति मेरी है; विशिष्ट उदाहरणों के लिए धन्यवाद। (हां, मुझे यह पता है, लेकिन यह "उच्च अधिकारियों" का हवाला देते हुए उपयोगी हो सकता है।)
14аn

1
@ डान: अगर आपको कुछ उद्धृत करने की आवश्यकता है, तो यह पोस्ट बेहतर होगी।
रवांग

1
@ डान: जॉन रेगर इस मुद्दे पर प्रोग्रामिंग भाषाओं में सक्रिय रूप से शोध कर रहे हैं। ब्लॉग
archives/

विरोधाभासी राय हैं: gustedt.wordpress.com/2013/07/15/…
rwong

14

यह उत्तर वास्तव में इस बात पर निर्भर करता है कि आपके कोड का उपयोग कौन करने जा रहा है, और वे कौन से मानक देखना चाहते हैं।

size_t एक पूर्णांक आकार एक उद्देश्य के साथ है:

प्रकार size_tएक कार्यान्वयन-परिभाषित अहस्ताक्षरित पूर्णांक प्रकार है जो किसी भी ऑब्जेक्ट के बाइट्स में आकार को शामिल करने के लिए पर्याप्त बड़ा है। (C ++ 11 विनिर्देशन 18.2.6)

इस प्रकार, जब भी आप बाइट्स में वस्तुओं के आकार के साथ काम करना चाहते हैं, तो आपको उपयोग करना चाहिएsize_t । अब कई मामलों में, आप बाइट्स गिनने के लिए इन आयामों / अनुक्रमकों का उपयोग नहीं कर रहे हैं, लेकिन अधिकांश डेवलपर्स size_tनिरंतरता के लिए उपयोग करना चुनते हैं ।

ध्यान दें कि आपको हमेशा उपयोग करना चाहिए size_tयदि आपकी कक्षा का उद्देश्य एसटीएल वर्ग की दिखना और महसूस करना है। विनिर्देश उपयोग में सभी एसटीएल वर्ग size_t यह कंपाइलर के लिए टाइप size_tकरने के लिए मान्य है unsigned int, और यह इसके लिए भी टाइप किए जाने के लिए मान्य है unsigned long। यदि आप उपयोग करते हैं intया longसीधे करते हैं, तो आप अंततः संकलक में चले जाएंगे, जहां एक व्यक्ति जो सोचता है कि आपकी कक्षा एसटीएल की शैली का पालन करती है, फंस जाती है क्योंकि आपने मानक का पालन नहीं किया था।

हस्ताक्षरित प्रकारों का उपयोग करने के लिए, कुछ फायदे हैं:

  • छोटे नाम - लोगों के लिए टाइप करना वास्तव में आसान है int, लेकिन कोड के साथ अव्यवस्था करना बहुत कठिन है unsigned int
  • प्रत्येक आकार के लिए एक पूर्णांक - 32-बिट्स का केवल एक CLS अनुरूप पूर्णांक है, जो कि Int32 है। C ++ में, दो ( int32_tऔर uint32_t) हैं। यह एपीआई इंटरऑपरेबिलिटी को सरल बना सकता है

हस्ताक्षरित प्रकारों का बड़ा नुकसान स्पष्ट है: आप अपने डोमेन का आधा हिस्सा खो देते हैं। एक हस्ताक्षरित संख्या एक अहस्ताक्षरित संख्या के रूप में उच्च गिनती नहीं कर सकती। जब C / C ++ आसपास आया, तो यह बहुत महत्वपूर्ण था। एक प्रोसेसर की पूरी क्षमता को संबोधित करने में सक्षम होने के लिए, और यह करने के लिए कि आपको अहस्ताक्षरित संख्याओं का उपयोग करने की आवश्यकता है।

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

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


चलो कहते हैं कि कार्यान्वयन size()था return bar_ * baz_;; क्या अब पूर्णांक ओवरफ़्लो (रैप-अराउंड) के साथ एक संभावित समस्या पैदा नहीं होती है जो कि अगर मैं उपयोग नहीं करता तो मेरे पास नहीं होता size_t?
Ðаn

5
@Dan आप ऐसे मामलों का निर्माण कर सकते हैं जहाँ अहस्ताक्षरित होना मायने रखता है, और उन मामलों में इसे हल करने के लिए पूर्ण भाषा सुविधाओं का उपयोग करना सबसे अच्छा है। हालाँकि, मुझे कहना होगा कि यह एक दिलचस्प निर्माण होगा जिसमें एक वर्ग होगा जहां bar_ * baz_हस्ताक्षर किए गए पूर्णांक को ओवरफ्लो किया जा सकता है लेकिन एक अहस्ताक्षरित पूर्णांक नहीं। C ++ में खुद को सीमित करना, यह ध्यान देने योग्य है कि अहस्ताक्षरित ओवरफ्लो को कल्पना में परिभाषित किया गया है, लेकिन हस्ताक्षरित ओवरफ्लो अपरिभाषित व्यवहार है, इसलिए यदि अहस्ताक्षरित पूर्णांकों के मॉडुलो अंकगणितीय वांछनीय हैं, तो निश्चित रूप से उनका उपयोग करें, क्योंकि यह वास्तव में परिभाषित है!
Cort Ammon

1
@Dan - अगरsize() overflowed पर हस्ताक्षर किए गुणा, आप भाषा यूबी देश में कर रहे हैं। (और fwrapvमोड में, अगला देखें :) जब बस, एक छोटे से मूत थोड़ा अधिक होता है, तो यह अहस्ताक्षरित गुणा से अधिक हो जाता है, आप उपयोगकर्ता-कोड-बग भूमि में - आप एक फर्जी आकार वापस कर देंगे। इसलिए मुझे नहीं लगता कि अहस्ताक्षरित यहाँ बहुत खरीदता है।
मार्टिन बा

4

मुझे लगता है कि ऊपर रवांग का जवाब पहले से ही मुद्दों पर उत्कृष्ट रूप से प्रकाश डालता है।

मैं अपना 002 जोड़ूंगा:

  • size_t, कि, एक आकार है कि ...

    किसी भी प्रकार (सरणी सहित) के सैद्धांतिक रूप से संभव वस्तु के अधिकतम आकार को स्टोर कर सकते हैं।

    ... केवल रेंज सूचकांकों के लिए आवश्यक sizeof(type)==1है, जब आप बाइट ( char) प्रकार के साथ काम कर रहे हैं । (लेकिन, हम ध्यान दें, यह एक ptr प्रकार से छोटा हो सकता है :

  • जैसे, xxx::size_type99.9% मामलों में इस्तेमाल किया जा सकता है , भले ही यह एक हस्ताक्षरित आकार का प्रकार हो। (तुलना करें ssize_t)
  • तथ्य यह है कि std::vectorऔर दोस्तों ने आकार और अनुक्रमण के लिए size_tएक अहस्ताक्षरित प्रकार को चुना , कुछ लोगों द्वारा डिजाइन दोष माना जाता है । मैं सहमत हूँ। (गंभीरता से, 5 मिनट लें और हल्की-फुल्की बातचीत देखें CppCon 2016: जॉन कल्ब "अहस्ताक्षरित: ए गाइडलाइन फॉर बेटर कोड" ।)
  • जब आप आज C ++ API डिज़ाइन करते हैं, तो आप एक तंग जगह पर होते हैं: size_tमानक लाइब्रेरी के अनुरूप होना, या उपयोग करना ( हस्ताक्षरित ) intptr_tया ssize_tआसान और कम बग प्रवण अनुक्रमण गणनाओं के लिए।
  • Int32 या int64 का उपयोग न करें - intptr_tयदि आप हस्ताक्षर करना चाहते हैं, और मशीन शब्द आकार, या उपयोग करना चाहते हैं, तो उपयोग करें ssize_t

सीधे सवाल का जवाब देने के लिए, यह पूरी तरह से "ऐतिहासिक संदर्भ" नहीं है, क्योंकि आधे से अधिक ("अनुक्रमण", या) पते की जगह को संबोधित करने की आवश्यकता के सैद्धांतिक मुद्दे को किसी भी तरह निम्न स्तर पर संबोधित किया जाना चाहिए, एहम, सी ++।

मसा में, मैं, व्यक्तिगत रूप से , लगता है, यह है एक डिजाइन दोष है कि स्टैंडर्ड लाइब्रेरी अहस्ताक्षरित का उपयोग करता है size_tसब जगह भी है, जहां यह एक कच्चे स्मृति आकार का प्रतिनिधित्व नहीं करता से अधिक है, लेकिन लिखे गए डेटा की क्षमता, संग्रह के लिए की तरह:

  • दिए गए C ++ s पूर्णांक पदोन्नति नियम ->
  • अहस्ताक्षरित प्रकार केवल "शब्दार्थ" प्रकार के लिए अच्छे उम्मीदवारों को किसी आकार के लिए नहीं बनाते हैं जो शब्दार्थ रूप से अहस्ताक्षरित है।

मैं जॉन की सलाह यहाँ दोहराऊंगा :

  • उन ऑपरेशनों के लिए प्रकारों का चयन करें जिनका वे समर्थन करते हैं (मूल्यों की श्रेणी नहीं)। (* 1)
  • आप एपीआई में अहस्ताक्षरित प्रकारों का उपयोग न करें। यह बग को बिना किसी लाभ के छुपाता है।
  • मात्रा के लिए "अहस्ताक्षरित" का उपयोग न करें। (* 2)

(* 1) यानी अहस्ताक्षरित == बिटमास्क, इस पर कभी गणित न करें (यहां पहला अपवाद हिट करता है - आपको एक काउंटर की आवश्यकता हो सकती है जो लपेटता है - यह एक अहस्ताक्षरित प्रकार होना चाहिए।)

(* 2) मात्राओं का अर्थ है कि आप कुछ गिनते हैं और / या गणित करते हैं।


"पूर्ण avilable फ्लैट मेमोरी" के साथ आपका क्या मतलब है? इसके अलावा, सुनिश्चित करें कि आप नहीं चाहते हैं ssize_t, size_tइसके बजाय हस्ताक्षरित लटकन के रूप में परिभाषित किया गया है intptr_t, जो किसी भी (गैर-सदस्य-) सूचक को संग्रहीत कर सकता है और इस प्रकार बड़ा हो सकता है?
डेडुप्लिकेटर

@Deduplicator - वैसे मुझे लगता है कि मैंने size_tपरिभाषा को थोड़ा गड़बड़ कर दिया है। देखें size_t बनाम intptr और en.cppreference.com/w/cpp/types/size_t आज कुछ सीखें। :-) मुझे लगता है कि बाकी तर्क खड़े हैं, मैं देखूंगा कि क्या मैं इस्तेमाल किए गए प्रकारों को ठीक कर सकता हूं।
मार्टिन बा

0

मैं सिर्फ इतना जोड़ता हूं कि प्रदर्शन के कारणों से मैं सामान्य रूप से size_t का उपयोग करता हूं, यह सुनिश्चित करने के लिए कि मिसकल्चुअल्स एक अंडरफ्लो का कारण बनता है जिसका अर्थ है कि दोनों रेंज चेक (शून्य से ऊपर और आकार के नीचे) () को एक तक कम किया जा सकता है:

प्रवेश किए हुए int का उपयोग करना:

int32_t i = GetRandomNumberFromRange(-1000, 1000);

if (i < 0)
{
    //error
}

if (i > size())
{
    //error
}

अहस्ताक्षरित int का उपयोग:

int32_t i = GetRandomNumberFromRange(-1000, 1000);

/// This will underflow any number below zero, so that it becomes a very big *positive* number instead.
uint32_t asUnsigned = static_cast<uint32_t>(i);

/// We now don't need to check for below zero, since an unsigned integer can only be positive.
if (asUnsigned > size())
{
    //error
}

1
आप वास्तव में एक और अच्छी तरह से समझाना चाहते हैं।
मार्टिन बा

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

मैंने इसे कुछ और समझाने की कोशिश की।
asger
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.