क्या मैं शून्य पर सेट "बाइट्स" के साथ मेम्कपी () और मेमोव () कॉल कर सकता हूं?


102

क्या मुझे ऐसे मामलों का इलाज करने की आवश्यकता है जब मेरे पास किनारे के मामलों के साथ memmove()/ कॉपी करने के लिए कुछ भी नहीं हैmemcpy()

int numberOfBytes = ...
if( numberOfBytes != 0 ) {
    memmove( dest, source, numberOfBytes );
}

या मुझे बिना जाँच के ही फ़ंक्शन को कॉल करना चाहिए

int numberOfBytes = ...
memmove( dest, source, numberOfBytes );

क्या पूर्व स्निपेट में जांच आवश्यक है?


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

12
@Toad: कोड को अव्यवस्थित करने के अलावा, क्या उद्देश्य है? किसी के कोड को पढ़ते समय, मुझे यह जानने की आवश्यकता नहीं है कि मूल प्रोग्रामर ने "इस ऑपरेशन को करने के बारे में सोचा था जो वास्तव में आवश्यक नहीं है, लेकिन क्योंकि यह अनावश्यक है, मैंने ऐसा नहीं किया"। यदि मैं एक सूचक को मुक्त करते हुए देखता हूं, तो मुझे पता है कि यह अशक्त होने की अनुमति है, इसलिए मुझे "मुझे शून्य की जांच करनी चाहिए" के विषय पर मूल प्रोग्रामर के विचारों को जानने की आवश्यकता नहीं है। और उसी के साथ 0 बाइट्स कॉपी करने के लिए जाता हैmemcpy
jalf

8
@ जैलफ: तथ्य यह है कि यह स्टैकओवरफ्लो पर एक सवाल है, यह कुछ लोगों को संदेह करता है। तो एक टिप्पणी जोड़ने से आपको मदद नहीं मिल सकती है, लेकिन कम ज्ञान वाले किसी व्यक्ति की मदद कर सकते हैं
Toad

2
@Toad हाँ, टिप्पणियां स्पष्ट रूप से बुला रही हैं कि एक चेक जो वास्तव में आवश्यक लगता है, सिद्धांत रूप में मूल्यवान नहीं हो सकता है। अन्य सिक्के के पक्ष कि इस विशिष्ट उदाहरण एक आम मामले एक मानक पुस्तकालय समारोह है कि प्रत्येक प्रोग्रामर केवल एक बार का जवाब जानने के लिए की जरूरत है शामिल है, तब वे पढ़े गए किसी भी कार्यक्रम में पहचान सकते हैं कि इन चेक की जरूरत नहीं है। के लिए है कि कारण, मैं टिप्पणी छोड़ चाहते हैं। इस तरह कई कॉल के साथ एक कोडबेस या तो टिप्पणियों को कॉपी करने और प्रत्येक को पेस्ट करने की आवश्यकता है, या मनमाने ढंग से केवल कुछ कॉल पर उनका उपयोग करें, जो दोनों बदसूरत हैं।
मार्क अमेरी

जवाबों:


145

C99 मानक (7.21.1 / 2) से:

जहां किसी size_t nफ़ंक्शन के लिए सरणी की लंबाई निर्दिष्ट करता है, nउस फ़ंक्शन के लिए कॉल पर मान शून्य हो सकता है। जब तक स्पष्ट रूप से अन्यथा इस उप-धारा में किसी विशेष कार्य के विवरण में कहा गया हो, ऐसे कॉल पर सूचक तर्क में अभी भी मान्य मान होंगे, जैसा कि 7.1.4 में वर्णित है। ऐसे कॉल पर, एक फ़ंक्शन जो किसी वर्ण का पता लगाता है, कोई घटना नहीं होती है, एक ऐसा फ़ंक्शन जो दो वर्ण अनुक्रमों की तुलना करता है शून्य, और एक फ़ंक्शन जो वर्णों की प्रतिलिपि बनाता है, शून्य वर्णों की प्रतिलिपि बनाता है।

तो उत्तर नहीं है; चेक आवश्यक नहीं है (या हाँ; आप शून्य पास कर सकते हैं)।


1
यदि किसी सरणी के अंतिम तत्व के बाद स्थान को इंगित किया जाता है, तो ऐसे फ़ंक्शन के प्रयोजनों के लिए एक पॉइंटर को "वैध" माना जाएगा? इस तरह के एक पॉइंटर को वैध रूप से स्थगित नहीं किया जा सकता है, लेकिन कोई अन्य पॉइंटर-ईश चीजों को सुरक्षित रूप से कर सकता है जैसे कि इसमें से एक को घटाएं।
सुपरकैट

1
@ सुपरकैट: हाँ, एक सूचक जो एक सरणी के अंत में एक अतीत को इंगित करता है, उस सरणी के भीतर (या एक के अंत में एक अतीत) के साथ अन्य अंक के साथ सूचक अंकगणितीय के लिए मान्य है, लेकिन dereferencable नहीं है।
माइक सीमोर

@MikeSeymour: प्रशस्ति पत्र का एक विपरीत उत्तर नहीं देना चाहिए: चेक आवश्यक है और आप शून्य मतदाताओं के साथ शून्य पास नहीं कर सकते?
neverhoodboy

7
@neverhoodboy: नहीं, उद्धरण स्पष्ट रूप से कहता है " nमूल्य शून्य हो सकता है"। आप सही हैं कि आप अशक्त बिंदुओं को पारित नहीं कर सकते, लेकिन यह वह नहीं है जिसके बारे में सवाल पूछ रहा है।
माइक सेमोर

1
@ मायकेस्मोर: मेरी गलती है। हृदय से क्षमाप्रार्थी। सवाल आकार नहीं सूचक के बारे में है।
neverhoodboy

5

जैसा कि @ यू ने कहा है, मानक निर्दिष्ट करता है कि मेमकी और मेमोव को इस मामले को समस्या के बिना संभालना चाहिए; चूंकि वे आमतौर पर किसी तरह लागू होते हैं

void *memcpy(void *_dst, const void *_src, size_t len)
{
    unsigned char *dst = _dst;
    const unsigned char *src = _src;
    while(len-- > 0)
        *dst++ = *src++;
    return _dst;
}

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


1
मुझे लगता है कि यह फ़ंक्शन शायद असेंबली में बनाया गया है जहां आप मेमोरी ट्रांसफ़र को सी में बेहतर कर सकते हैं
टॉड

"किसी तरह" :) वास्तव में मैंने देखा लगभग सभी कार्यान्वयन विधानसभा में हैं, और मूल शब्द आकार (जैसे x 86 पर uint32_t) का उपयोग करके अधिकांश बिट्स को कॉपी करने की कोशिश करते हैं, लेकिन यह उत्तर के पदार्थ को नहीं बदलता है : यह एक समय का लूप है जिसे शुरू करने से पहले महान गणना की आवश्यकता नहीं है, इसलिए चेक पहले से ही किया गया है।
मट्टियो इतालिया

9
-1, सामान्य कार्यान्वयन अप्रासंगिक है कि क्या यह सी (इन कार्यों को भी सी फ़ंक्शन के रूप में लागू नहीं किया जा सकता है) को कॉल करने के लिए मान्य है।
आर .. गिटहब स्टॉप हेल्पिंग ICE

4
तथ्य यह है कि यह वैध सी है पहले से ही अन्य उत्तरों द्वारा कवर किया गया है, जैसा कि मैंने अपने जवाब की शुरुआत में कहा था: "जैसा कि आपने @ कहा था, मानक निर्दिष्ट करता है कि मेमकी और मेमोव को इस मामले को बिना समस्या के संभालना चाहिए"। मैंने सिर्फ इस तथ्य पर अपनी राय जोड़ी है कि आपको प्रदर्शन के कारणों के लिए len = 0 के साथ कॉल करने का डर भी नहीं होना चाहिए, क्योंकि उस मामले में यह लगभग शून्य लागत वाला कॉल है।
मैटियो इटालिया
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.