2010-10-31 7 views
13

ठीक है, मैं पूरी तरह से एक नौसिखिया नहीं हूं, लेकिन मैं नहीं कह सकता कि मैं निम्नलिखित मैक्रो को समझता हूं। सबसे भ्रमित हिस्सा मूल्य कास्ट आकार_टी के साथ विभाजन है: पृथ्वी पर क्या वह पूरा करता है? विशेष रूप से, चूंकि मुझे एक निषेध ऑपरेटर दिखाई देता है, जहां तक ​​मुझे पता है, परिणामस्वरूप शून्य मान हो सकता है। इसका मतलब यह नहीं है कि यह एक विभाजन-दर-शून्य त्रुटि का कारण बन सकता है?ARRAYSIZE C++ मैक्रो: यह कैसे काम करता है?

#define ARRAYSIZE(a) \ 
    ((sizeof(a)/sizeof(*(a)))/\ 
    static_cast<size_t>(!(sizeof(a) % sizeof(*(a))))) 
+3

इस पूरी बात है? के लिए '# endif' क्या है? –

उत्तर

12

पहले भाग (sizeof(a)/sizeof(*(a))) काफी सरल है (वैसे, मैक्रो सही खूबसूरती से है और काम करता है।); यह पूरे तत्व के आकार से पूरे सरणी के आकार को विभाजित कर रहा है (माना जाता है कि आप मैक्रो को सरणी प्रकार का ऑब्जेक्ट पास करते हैं, न कि पॉइंटर)। यह सरणी में तत्वों की संख्या देता है।

दूसरा भाग इतना सरल नहीं है। मुझे लगता है कि संभावित विभाजन-दर-शून्य जानबूझकर है; यह एक संकलन-समय त्रुटि का कारण बन जाएगा यदि किसी भी कारण से, सरणी का आकार इसके तत्वों में से एक का पूर्णांक नहीं है। दूसरे शब्दों में, यह किसी प्रकार की संकलन-समय संवेदना जांच है।

हालांकि, मैं इस किन परिस्थितियों में हो सकता है के तहत नहीं देख सकते हैं ... लोगों को नीचे टिप्पणी में सुझाव दिया है के रूप में, यह कुछ दुरुपयोग (एक सूचक पर ARRAYSIZE() का उपयोग कर की तरह) पकड़ लेंगे। हालांकि, इस तरह की सभी त्रुटियों को नहीं पकड़ेगा।

+0

मुझे लगता है कि यह मैक्रो के कभी-कभी दुरुपयोग को पकड़ने के लिए है, जैसे इसे एक सरणी के बजाए पॉइंटर पर कॉल करना। दुर्भाग्यवश, यह किसी ऑब्जेक्ट पर पॉइंटर पर कॉल करने जैसी चीज़ों को नहीं पकड़ती है जो पॉइंटर के समान आकार है। –

+1

मुख्य परिस्थिति मैं सोच सकता हूं कि जब 'ए' एक सूचक होता है, जिसका आकार 'आकार (ए) 'का कारक नहीं होता है। तो अधिकांश कक्षाएं, आप उम्मीद करेंगे, लेकिन यदि आप 'a'' char * 'हैं तो आपको वांछित विभाजन-दर-शून्य नहीं मिलेगा। C++ में ARRAYSIZE सहायक को लिखने के बेहतर तरीके हैं ताकि एक पॉइंटर के साथ उपयोग होने पर चेतावनी/त्रुटि प्राप्त हो सके। और यह 'static_cast' की वजह से केवल C++ है, दोहरी उपयोग C++ और C नहीं है। –

1

यह एक विभाजन-दर-शून्य त्रुटि (जानबूझकर) का कारण बनता है। जिस तरह से यह मैक्रो काम करता है वह बाइट्स में एक सरणी तत्व के आकार से बाइट में सरणी के आकार को विभाजित करता है। इसलिए यदि आपके पास int मानों की एक सरणी है, जहां int 4 बाइट्स (अधिकतम 32-बिट मशीनों पर) है, तो 4 int मानों की एक सरणी 16 बाइट्स होगी।

तो जब आप इस मैक्रो को इस तरह के सरणी पर कॉल करते हैं, तो यह sizeof(array)/sizeof(*array) करता है। और 16/4 = 4 के बाद से, यह लौटाता है कि सरणी में 4 तत्व हैं।

नोट: *array सरणी के पहले तत्व को संदर्भित करता है और array[0] के बराबर है।

दूसरा विभाजन मॉड्यूलो-डिवीजन (विभाजन का शेष प्राप्त करता है) करता है, और चूंकि किसी भी गैर-शून्य मान को "सत्य" माना जाता है, ! ऑपरेटर का उपयोग करके विभाजन का शेष शून्य होता है यदि विभाजन का शेष है गैर-शून्य (और इसी तरह, 1 अन्यथा विभाजन)।

3

लगता है हम

T arr[42]; 

ARRAYSIZE(arr) के लिए (मोटे तौर पर)

sizeof (arr)/sizeof(*arr)/!(sizeof(arr) % sizeof(*arr)) 

जो इस मामले में देता है 42 /! 0 जो 42

है का विस्तार होगा किसी कारण sizeof सरणी के लिए तो इसके तत्व के आकार से विभाजित नहीं है, शून्य से विभाजन होगा। यह कब हो सकता है? उदाहरण के लिए जब आप एक स्थिर की बजाय गतिशील रूप से आवंटित सरणी पास करते हैं!

6

अंत में विभाजन एक गैर-सरणी तर्क (उदा। पॉइंटर) का पता लगाने पर प्रयास लगता है।

यह उदाहरण के लिए, char* का पता लगाने में विफल रहता है, लेकिन T* के लिए काम करेगा जहां sizeof(T) पॉइंटर के आकार से अधिक है।

typedef ptrdiff_t Size; 

template< class Type, Size n > 
Size countOf(Type (&)[n]) { return n; } 

इस समारोह टेम्पलेट सूचक तर्क, केवल सरणी के साथ instantiated नहीं किया जा सकता है:

सी ++ में, एक आम तौर पर निम्नलिखित समारोह टेम्पलेट पसंद करती हैं। सी ++ 11 में इसे वैकल्पिक रूप से std::begin और std::end के संदर्भ में व्यक्त किया जा सकता है, जो स्वचालित रूप से इसे यादृच्छिक एक्सेस इटरेटर्स के साथ मानक कंटेनर के लिए भी काम करने देता है।

सीमाएं: C++ 03 में स्थानीय प्रकार की सरणी के लिए काम नहीं करती है, और संकलन समय आकार उत्पन्न नहीं करती है। सभी कोड संकलक के हाथों से अछूता:

संकलन समय आकार के लिए आप के बजाय तरह

template< Size n > struct Sizer { char elems[n]; }; 

template< class Type, size n > 
Sizer<n> countOf_(Type (&)[n]); 

#define COUNT_OF(a) sizeof(countOf_(a).elems) 

अस्वीकरण कर सकते हैं।

लेकिन सामान्य रूप से, केवल पहले फ़ंक्शन टेम्पलेट का उपयोग करें, countOf

चीयर्स & एचएचटी।

0

div-by-zero किसी भी कारण से संरेखण त्रुटियों को पकड़ने का प्रयास कर रहा है। जैसे, कुछ कंपाइलर सेटिंग्स के साथ, सरणी तत्व का आकार 3 था, लेकिन कंपाइलर तेज़ सरणी पहुंच के लिए इसे 4 तक गोल करेगा, फिर 4 प्रविष्टियों की एक सरणी का आकार 16 होगा और! (16/3) जाएगा शून्य पर, संकलन समय पर विभाजन-दर-शून्य देना। फिर भी, मुझे ऐसा करने वाले किसी भी कंपाइलर के बारे में पता नहीं है, और यह उस आकार के आकार से भिन्न आकार के आकार के लिए सी ++ के विनिर्देश के खिलाफ हो सकता है जो उस प्रकार के आकार से अलग है ..

-1

देर से आ रहा है यहां पार्टी ...

गूगल के सी ++ codebase IMHO निश्चित सी ++ arraysize() के कार्यान्वयन मैक्रो है, जो कई झुर्रियां पड़ने यहाँ नहीं माना जाता है भी शामिल है।

मैं the source पर सुधार नहीं कर सकता, जिसमें स्पष्ट और पूर्ण टिप्पणियां हैं।

1

मैंने इस मैक्रो के इस संस्करण को लिखा था। पुराने संस्करण पर विचार करें:

sizeof stats = 4608 
sizeof *stats = 144 
ARRAYSIZE=32 
sizeof stats = 8 
sizeof *stats = 144 
ARRAYSIZE=0 

क्या हो रहा है:

#include <sys/stat.h> 
#define ARRAYSIZE(a) (sizeof(a)/sizeof(*(a))) 

int main(int argc, char *argv[]) { 
    struct stat stats[32]; 
    std::cout << "sizeof stats = " << (sizeof stats) << "\n"; 
    std::cout << "sizeof *stats = " << (sizeof *stats) << "\n"; 
    std::cout << "ARRAYSIZE=" << ARRAYSIZE(stats) << "\n"; 

    foo(stats); 
} 

void foo(struct stat stats[32]) { 
    std::cout << "sizeof stats = " << (sizeof stats) << "\n"; 
    std::cout << "sizeof *stats = " << (sizeof *stats) << "\n"; 
    std::cout << "ARRAYSIZE=" << ARRAYSIZE(stats) << "\n"; 
} 

64-बिट मशीन पर, इस कोड को इस उत्पादन उत्पादन होता है? ARRAYSIZE 32 से शून्य तक कैसे चला गया? खैर, समस्या यह है कि फ़ंक्शन पैरामीटर वास्तव में एक सूचक है, भले ही यह एक सरणी जैसा दिखता हो। तो foo के अंदर, "sizeof (आँकड़े)" 8 बाइट्स, और "sizeof (* आँकड़े)" है अभी भी 144

नया मैक्रो के साथ

है:

#define ARRAYSIZE(a) \ 
    ((sizeof(a)/sizeof(*(a)))/\ 
    static_cast<size_t>(!(sizeof(a) % sizeof(*(a))))) 

जब sizeof (क) नहीं है आकार के एक से अधिक (* (ए)),% शून्य नहीं है, जो! इनवर्ट्स, और फिर static_cast शून्य पर मूल्यांकन करता है, जिससे संकलन-समय विभाजन शून्य हो जाता है। तो मैक्रो में यथासंभव संभव है, यह अजीब विभाजन संकलन समय पर समस्या को पकड़ता है।

पुनश्च: सी ++ 17 में, बस std :: आकार का उपयोग करें, देखें http://en.cppreference.com/w/cpp/iterator/size

संबंधित मुद्दे