नॉन-कास्ट और पॉइंटर को पॉइंटर के साथ फंक्शन कॉल उसी पते के कॉन्स्टिट्यूशन को कांस्टीट्यूशन के लिए


14

मैं एक फ़ंक्शन लिखना चाहता हूं जो डेटा का एक सरणी इनपुट करता है और पॉइंटर्स का उपयोग करके डेटा का एक और सरणी आउटपुट करता है।

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

void f(const char *src, char *dst) {
    dst[2] = src[0];
    dst[1] = src[1];
    dst[0] = src[2];
}

int main() {
    char s[] = "123";
    f(s,s);
    printf("%s\n", s);
    return 0;
}

उपरोक्त प्रश्न के अलावा, क्या यह अच्छी तरह से परिभाषित है अगर मैं constमूल कोड में हटाऊं ?

जवाबों:


17

हालांकि यह सच है कि व्यवहार अच्छी तरह से परिभाषित है - यह सच नहीं है कि संकलक इस अर्थ में "कास्ट के लिए अनुकूलन" कर सकते हैं जिसका अर्थ है।

यही है, एक संकलक को यह मानने की अनुमति नहीं है कि सिर्फ इसलिए कि एक पैरामीटर एक है const T* ptr, द्वारा इंगित की गई मेमोरी को ptrदूसरे पॉइंटर के माध्यम से नहीं बदला जाएगा। संकेत भी बराबर होने की जरूरत नहीं है। constआप से एक दायित्व (समारोह =) है कि सूचक के माध्यम से परिवर्तन करने के लिए नहीं - एक दायित्व है, गारंटी नहीं।

वास्तव में उस गारंटी के लिए, आपको restrictकीवर्ड के साथ पॉइंटर को चिह्नित करना होगा । इस प्रकार, यदि आप इन दो कार्यों को संकलित करते हैं:

int foo(const int* x, int* y) {
    int result = *x;
    (*y)++;
    return result + *x;
}

int bar(const int* x, int* restrict y) {
    int result = *x;
    (*y)++;
    return result + *x;
}

foo()समारोह से दो बार अवश्य पढ़ें x, जबकि bar()केवल एक बार इसे पढ़ने के लिए की जरूरत है:

foo:
        mov     eax, DWORD PTR [rdi]
        add     DWORD PTR [rsi], 1
        add     eax, DWORD PTR [rdi]  # second read
        ret
bar:
        mov     eax, DWORD PTR [rdi]
        add     DWORD PTR [rsi], 1
        add     eax, eax              # no second read
        ret

इस पर लाइव देखें GodBolt

restrictC में केवल एक कीवर्ड है (C99 के बाद से); दुर्भाग्य से, इसे अभी तक C ++ में पेश नहीं किया गया है (खराब कारण के लिए जो इसे C ++ में पेश करने के लिए अधिक जटिल है)। कई कंपाइलर थोड़े सपोर्ट करते हैं, हालाँकि, जैसा कि __restrict

नीचे पंक्ति: संकलक को संकलन करते समय आपके "गूढ़" उपयोग मामले का समर्थन करना चाहिए f(), और इसके साथ कोई समस्या नहीं होगी।


के लिए उपयोग मामलों के बारे में यह पोस्ट देखें restrict


constनहीं है "आप (= समारोह) द्वारा एक दायित्व उस सूचक के माध्यम से परिवर्तन करने के लिए नहीं"। सी मानक constएक डाली के माध्यम से समारोह को हटाने और फिर परिणाम के माध्यम से वस्तु को संशोधित करने की अनुमति देता है । अनिवार्य रूप से, constकिसी वस्तु को अनजाने में संशोधित करने से बचने में मदद करने के लिए सिर्फ सलाहकार और प्रोग्रामर के लिए एक सुविधा है।
एरिक पोस्टपिसिल

@ EricPostpischil: यह एक दायित्व है जिससे आप बाहर निकल सकते हैं।
ईनपोकलम

आप जिस दायित्व से बाहर निकल सकते हैं वह दायित्व नहीं है।
एरिक पोस्टपिसिल

2
@ EricPostpischil: 1. तुम यहाँ बाल काट रहे हो। 2. यह सच नहीं है।
ईनपोकलम

1
यही कारण है कि memcpyऔर strcpyके साथ घोषणा की जाती है restrict, तर्क, जबकि memmoveनहीं है - केवल बाद स्मृति ब्लॉकों के बीच ओवरलैप अनुमति देता है।
बरमार

5

यह अच्छी तरह से परिभाषित है (सी ++ में, सी में निश्चित नहीं है), constक्वालीफायर के साथ और बिना ।

पहली बात यह है कि सख्त अलियासिंग नियम 1 है । यदि srcऔर dstएक ही वस्तु को इंगित करता है:

constक्वालीफायर के बारे में , आप यह तर्क दे सकते हैं कि जब से dst == srcआपका फ़ंक्शन प्रभावी रूप से srcइंगित करता है कि , srcकिस रूप में योग्य नहीं होना चाहिए const। यह कैसे constकाम करता है। दो मामलों पर विचार करने की आवश्यकता है:

  1. जब किसी वस्तु को परिभाषित किया जाता है const, जैसे कि char const data[42];, इसे (प्रत्यक्ष या अप्रत्यक्ष रूप से) संशोधित करने से अपरिभाषित व्यवहार होता है।
  2. जब किसी constवस्तु के संदर्भ या सूचक को परिभाषित किया जाता है, तो जैसे char const* pdata = data;कोई अंतर्निहित वस्तु को संशोधित कर सकता है बशर्ते उसे const2 के रूप में परिभाषित नहीं किया गया हो (देखें 1.)। तो निम्नलिखित अच्छी तरह से परिभाषित है:
int main()
{
    int result = 42;
    int const* presult = &result;
    *const_cast<int*>(presult) = 0;
    return *presult; // 0
}

1) सख्त अलियासिंग नियम क्या है?
2) है const_castसुरक्षित?


हो सकता है कि ओपी का अर्थ है असाइनमेंट्स का संभावित पुन: निर्धारण?
इगोर आर।

char*और char const*संगत नहीं हैं। _Generic((char *) 0, const char *: 1, default: 0))शून्य का मूल्यांकन करता है।
एरिक पोस्टपिसिल

“जब एक संदर्भ या किसी constवस्तु के लिए एक सूचक परिभाषित किया जाता है” तो यह गलत है। आप का मतलब है कि जब एक const-क्वालिफ़ाइड प्रकार के लिए एक संदर्भ या सूचक परिभाषित किया गया है, तो इसका मतलब यह नहीं है कि जिस वस्तु को इंगित करना है वह संशोधित नहीं हो सकता है (विभिन्न तरीकों से)। (यदि पॉइंटर किसी constऑब्जेक्ट को इंगित करता है , तो इसका मतलब है कि ऑब्जेक्ट वास्तव constमें परिभाषा के अनुसार है, इसलिए संशोधित करने की कोशिश करने का व्यवहार परिभाषित नहीं है।)
एरिक पोस्टपिसिल

@ एरिक, मैं केवल वह विशिष्ट हूं जब प्रश्न मानक या टैग के बारे में हो language-lawyer। सटीक एक मूल्य है जो मैं संजोता हूं, लेकिन मैं यह भी जानता हूं कि यह अधिक जटिलता के साथ आता है। यहाँ, मैंने सरलता और आसानी से समझने वाले वाक्यों के लिए जाने का फैसला किया है, क्योंकि मुझे लगता है कि यह वाट ओपी चाहता था। अगर आपको लगता है कि कृपया उत्तर दें, तो मैं इसे सबसे पहले लाने वालों में से हूँ। वैसे भी, आपकी टिप्पणी के लिए धन्यवाद।
YSC

3

सी। में यह अच्छी तरह से परिभाषित है। सख्त एलियासिंग नियम इसके साथ लागू नहीं होते हैं char टाइप के , न ही एक ही प्रकार के दो पॉइंटर्स के साथ।

मुझे यकीन नहीं है कि आप "के लिए अनुकूलित करें" से क्या मतलब है const। मेरा कंपाइलर (GCC 8.3.0 x86-64) दोनों मामलों के लिए एक ही कोड बनाता है। यदि आप जोड़ते हैंrestrict निर्दिष्ट करने वाले बिंदुओं को , तो उत्पन्न कोड थोड़ा बेहतर है, लेकिन यह आपके मामले के लिए काम नहीं करेगा, संकेत समान हैं।

(C11 C6.5 7)

एक वस्तु का संग्रहित मूल्य केवल एक लैवल्यू एक्सप्रेशन द्वारा एक्सेस किया जाता है, जिसमें निम्न में से एक प्रकार होता है:
- एक प्रकार का ऑब्जेक्ट प्रभावी प्रकार के साथ संगत होता है,
- ऑब्जेक्ट के प्रभावी प्रकार के साथ संगत एक प्रकार का एक योग्य संस्करण,
- एक प्रकार जो वस्तु के प्रभावी प्रकार के अनुसार हस्ताक्षरित या अहस्ताक्षरित प्रकार है,
- एक प्रकार जो हस्ताक्षरित या अहस्ताक्षरित प्रकार है जो वस्तु के प्रभावी प्रकार के योग्य संस्करण के अनुरूप है,
- एक समग्र या संघ प्रकार जिसमें एक शामिल है इसके सदस्यों के बीच पूर्वोक्त प्रकारों में (सहित, पुनरावर्ती, उपसमूह या निहित संघ का सदस्य), या
- एक चरित्र प्रकार।

इस मामले में (बिना restrict), आपको हमेशा 121परिणाम मिलेगा ।

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