C ++ में प्रतिबंधित कीवर्ड का क्या मतलब है?


182

मैं हमेशा अनिश्चित था, C ++ में प्रतिबंधित कीवर्ड का क्या मतलब है?

क्या इसका मतलब यह है कि फ़ंक्शन को दिए गए दो या अधिक सूचक ओवरलैप नहीं करते हैं? इसका और क्या मतलब है?


23
restrictएक c99 कीवर्ड है। हां, आरबर्ट एस। बार्न्स, मुझे पता है कि अधिकांश कंपाइलर समर्थन करते हैं __restrict__। आप ध्यान देंगे कि डबल अंडरस्कोर के साथ कुछ भी है, परिभाषा के अनुसार, कार्यान्वयन विशिष्ट है और इस प्रकार सी ++ नहीं है , लेकिन इसका एक संकलक विशिष्ट संस्करण है।
KitsuneYMG

5
क्या? सिर्फ इसलिए कि यह कार्यान्वयन विशिष्ट है, यह C ++ नहीं बनाता है; C ++ स्पष्ट रूप से विशिष्ट सामान को लागू करने की अनुमति देता है, और इसे अस्वीकार नहीं करता है या इसे C ++ नहीं करता है।
ऐलिस

4
@ एलाइस किट्सयूएनवाईएमजी का मतलब है कि यह आईएसओ सी ++ का हिस्सा नहीं है, और इसके बजाय सी ++ एक्सटेंशन माना जाता है। कंपाइलर रचनाकारों को अपने स्वयं के एक्सटेंशन बनाने और वितरित करने की अनुमति है, जो आईएसओ सी ++ के साथ सह-अस्तित्व में है और सी ++ के लिए आमतौर पर कम-या-गैर-पोर्टेबल अनौपचारिक जोड़ के रूप में कार्य करता है। उदाहरण MS के पुराने प्रबंधित C ++ और उनके हाल के C ++ / CLI होंगे। अन्य उदाहरण कुछ संकलक द्वारा आपूर्ति किए गए प्रीप्रोसेसर निर्देश और मैक्रोज़ होंगे, जैसे कि सामान्य #warningनिर्देश, या फ़ंक्शन हस्ताक्षर मैक्रोज़ ( __PRETTY_FUNCTION__जीसीसी __FUNCSIG__पर, एमएसवीसी आदि)।
जस्टिन टाइम -

4
@ मेरी जानकारी के लिए, C ++ 11 C99 के सभी के लिए पूर्ण समर्थन को अनिवार्य नहीं करता है, न ही C ++ 14 या मुझे C ++ 17 के बारे में क्या पता है। restrictC ++ कीवर्ड नहीं माना जाता है ( en.cppreference.com/w/cpp/keyword देखें ), और वास्तव restrictमें, C ++ 11 मानक में एकमात्र उल्लेख ( देखें-std.org/jtc1/sc22/wg21 /docs/papers/2012/n3337.pdf , मामूली संपादकीय परिवर्तनों के साथ FDIS की एक प्रति, library17.2 [पुस्तकालय.c], पीडीएफ पृष्ठ 413) में कहा गया है कि:
जस्टिन समय -

4
@ ऐलिस ऐसा कैसे? मैं बात यह है कि का कहना है कि कहा गया है restrictकिया जा रहा है में शामिल करना ज़रूरी (से बाहर रखा गया, के बाहर छोड़ दिया) सी मानक पुस्तकालय समारोह हस्ताक्षर और शब्दों को जब उन कार्यों सी ++ मानक पुस्तकालय में शामिल हैं। या दूसरे शब्दों में, मैंने इस तथ्य को कहा कि यदि सी मानक लाइब्रेरी फ़ंक्शन के हस्ताक्षर restrictमें सी है, तो restrictकीवर्ड को C ++ के समकक्ष हस्ताक्षर से हटा दिया जाना चाहिए।
जस्टिन टाइम -

जवाबों:


143

अपने पेपर में, मेमोरी ऑप्टिमाइज़ेशन , क्रिस्टरन का कहना है कि restrictअभी तक C ++ मानक का हिस्सा नहीं है, कि यह कई कंपाइलरों द्वारा समर्थित है और वे उपलब्ध होने पर इसका उपयोग करने की सलाह देते हैं:

कीवर्ड प्रतिबंधित करें

! 1999 से एएनएसआई / आईएसओ सी मानक

! अभी तक C ++ मानक में नहीं है, लेकिन कई C ++ कंपाइलर द्वारा समर्थित है

! केवल एक संकेत है, इसलिए कुछ भी नहीं कर सकते हैं और अभी भी अनुरूप हो सकते हैं

एक प्रतिबंधित-योग्य सूचक (या संदर्भ) ...

! ... मूल रूप से कंपाइलर को एक वादा है कि पॉइंटर के दायरे के लिए, पॉइंटर का लक्ष्य केवल उस पॉइंटर (और इससे कॉपी किए गए पॉइंटर्स) के माध्यम से एक्सेस किया जाएगा।

C ++ कंपाइलर में जो इसे सपोर्ट करता है उसे संभवतः C के समान व्यवहार करना चाहिए।

विवरण के लिए इस SO पोस्ट को देखें: C99 'प्रतिबंधित' कीवर्ड का यथार्थवादी उपयोग?

आधे घंटे ले लो स्किमर्स पेपर के माध्यम से, यह दिलचस्प और समय के लायक है।

संपादित करें

मैंने यह भी पाया कि IBM का AIX C / C ++ कंपाइलर __restrict__कीवर्ड का समर्थन करता है

g ++ भी इसका समर्थन करता प्रतीत होता है क्योंकि निम्न प्रोग्राम g ++ पर सफाई से संकलित है:

#include <stdio.h>

int foo(int * __restrict__ a, int * __restrict__ b) {
    return *a + *b;
}

int main(void) {
    int a = 1, b = 1, c;

    c = foo(&a, &b);

    printf("c == %d\n", c);

    return 0;
}

मुझे इसके उपयोग पर एक अच्छा लेख भी मिला restrict:

प्रतिबंधित खोजशब्द को नष्ट करना

EDIT2

मैं एक लेख पर भाग गया, जो विशेष रूप से C ++ प्रोग्राम में प्रतिबंधित के उपयोग पर चर्चा करता है:

लोड-हिट-स्टोर और __restrict कीवर्ड

साथ ही, Microsoft Visual C ++ भी __restrictकीवर्ड का समर्थन करता है


2
मेमोरी ऑप्टिमाइज़ेशन पेपर लिंक मृत है, यहाँ उसकी जीडीसी प्रस्तुति से ऑडियो का लिंक है। gdcvault.com/play/1022689/Memory
ग्रिम्मे

1
@EnnMichael: जाहिर है अगर आप इसे पोर्टेबल C ++ प्रोजेक्ट में इस्तेमाल करने जा रहे हैं, तो आपको ऐसा ही करना चाहिए #ifndef __GNUC__ #define __restrict__ /* no-op */। और __restrictअगर परिभाषित किया गया है तो _MSC_VERइसे परिभाषित करें।
पीटर कॉर्डेस

96

जैसा कि अन्य लोगों ने कहा है, यदि C ++ 14 का कोई मतलब नहीं है , तो आइए __restrict__GCC विस्तार पर विचार करें जो C99 के समान है restrict

C99

restrictकहते हैं कि दो पॉइंटर्स ओवरलैपिंग मेमोरी क्षेत्रों को इंगित नहीं कर सकते हैं। फ़ंक्शन तर्कों के लिए सबसे आम उपयोग है।

यह बताता है कि फ़ंक्शन को कैसे बुलाया जा सकता है, लेकिन अधिक संकलन अनुकूलन के लिए अनुमति देता है।

यदि कॉलर restrictअनुबंध, अपरिभाषित व्यवहार का पालन नहीं करता है।

C99 N1256 मसौदा 6.7.3 / 7 "प्रकार क्वालिफायर" कहते हैं:

प्रतिबंधित क्वालीफायर का उपयोग (रजिस्टर स्टोरेज क्लास की तरह) अनुकूलन को बढ़ावा देने के लिए है, और एक अनुरूप कार्यक्रम की रचना करने वाले सभी प्रीप्रोसेसिंग अनुवाद इकाइयों से क्वालिफायर के सभी उदाहरणों को हटाने से इसका अर्थ (यानी, नमूदार व्यवहार) नहीं बदलता है।

और 6.7.3.1 "प्रतिबंधित की औपचारिक परिभाषा" गोर विवरण देती है।

एक संभावित अनुकूलन

विकिपीडिया उदाहरण है बहुत रोशन।

यह स्पष्ट रूप से दिखाता है कि कैसे यह एक विधानसभा निर्देश को बचाने की अनुमति देता है

बिना प्रतिबंधित:

void f(int *a, int *b, int *x) {
  *a += *x;
  *b += *x;
}

छद्म विधानसभा:

load R1  *x    ; Load the value of x pointer
load R2  *a    ; Load the value of a pointer
add R2 += R1    ; Perform Addition
set R2  *a     ; Update the value of a pointer
; Similarly for b, note that x is loaded twice,
; because a may be equal to x.
load R1  *x
load R2  *b
add R2 += R1
set R2  *b

प्रतिबंधित के साथ:

void fr(int *__restrict__ a, int *__restrict__ b, int *__restrict__ x);

छद्म विधानसभा:

load R1  *x
load R2  *a
add R2 += R1
set R2  *a
; Note that x is not reloaded,
; because the compiler knows it is unchanged
; load R1  *x
load R2  *b
add R2 += R1
set R2  *b

क्या जीसीसी वास्तव में ऐसा करता है?

g++ 4.8 लिनक्स x86-64:

g++ -g -std=gnu++98 -O0 -c main.cpp
objdump -S main.o

के साथ -O0, वे समान हैं।

के साथ -O3:

void f(int *a, int *b, int *x) {
    *a += *x;
   0:   8b 02                   mov    (%rdx),%eax
   2:   01 07                   add    %eax,(%rdi)
    *b += *x;
   4:   8b 02                   mov    (%rdx),%eax
   6:   01 06                   add    %eax,(%rsi)  

void fr(int *__restrict__ a, int *__restrict__ b, int *__restrict__ x) {
    *a += *x;
  10:   8b 02                   mov    (%rdx),%eax
  12:   01 07                   add    %eax,(%rdi)
    *b += *x;
  14:   01 06                   add    %eax,(%rsi) 

बिन बुलाए के लिए, सम्मेलन बुला रहा है:

  • rdi = पहला पैरामीटर
  • rsi = दूसरा पैरामीटर
  • rdx = तीसरा पैरामीटर

जीसीसी आउटपुट विकी लेख से भी अधिक स्पष्ट था: 4 निर्देश बनाम 3 निर्देश।

Arrays

अब तक हमारे पास एकल निर्देश बचत है, लेकिन अगर सूचक एक सामान्य उपयोग के मामले में लूप किए जाने के लिए सरणियों का प्रतिनिधित्व करता है, तो निर्देशों का एक गुच्छा बचाया जा सकता है, जैसा कि सुपरकैट और माइकल द्वारा उल्लेख किया गया है ।

उदाहरण के लिए विचार करें:

void f(char *restrict p1, char *restrict p2, size_t size) {
     for (size_t i = 0; i < size; i++) {
         p1[i] = 4;
         p2[i] = 9;
     }
 }

के कारण restrict, एक स्मार्ट संकलक (या मानव), को अनुकूलित कर सकता है:

memset(p1, 4, size);
memset(p2, 9, size);

जो संभावित रूप से बहुत अधिक कुशल है क्योंकि यह एक सभ्य libc कार्यान्वयन (जैसे glibc) पर असेंबली अनुकूलित किया जा सकता है क्या प्रदर्शन के संदर्भ में std :: memcpy () या std :: copy () का उपयोग करना बेहतर है? , संभवतः SIMD के निर्देशों के साथ ।

बिना प्रतिबंधित, यह अनुकूलन नहीं किया जा सकता है, उदाहरण पर विचार करें:

char p1[4];
char *p2 = &p1[1];
f(p1, p2, 3);

फिर forसंस्करण बनाता है:

p1 == {4, 4, 4, 9}

जबकि memsetसंस्करण बनाता है:

p1 == {4, 9, 9, 9}

क्या जीसीसी वास्तव में ऐसा करता है?

GCC 5.2.1.लिन्क्स x86-64 उबंटू 15.10:

gcc -g -std=c99 -O0 -c main.c
objdump -dr main.o

के साथ -O0, दोनों समान हैं।

के साथ -O3:

  • प्रतिबंध के साथ:

    3f0:   48 85 d2                test   %rdx,%rdx
    3f3:   74 33                   je     428 <fr+0x38>
    3f5:   55                      push   %rbp
    3f6:   53                      push   %rbx
    3f7:   48 89 f5                mov    %rsi,%rbp
    3fa:   be 04 00 00 00          mov    $0x4,%esi
    3ff:   48 89 d3                mov    %rdx,%rbx
    402:   48 83 ec 08             sub    $0x8,%rsp
    406:   e8 00 00 00 00          callq  40b <fr+0x1b>
                            407: R_X86_64_PC32      memset-0x4
    40b:   48 83 c4 08             add    $0x8,%rsp
    40f:   48 89 da                mov    %rbx,%rdx
    412:   48 89 ef                mov    %rbp,%rdi
    415:   5b                      pop    %rbx
    416:   5d                      pop    %rbp
    417:   be 09 00 00 00          mov    $0x9,%esi
    41c:   e9 00 00 00 00          jmpq   421 <fr+0x31>
                            41d: R_X86_64_PC32      memset-0x4
    421:   0f 1f 80 00 00 00 00    nopl   0x0(%rax)
    428:   f3 c3                   repz retq

    memsetउम्मीद के मुताबिक दो कॉल।

  • बिना प्रतिबंधित: कोई stdlib कॉल, सिर्फ 16 पुनरावृत्ति वाइड लूप unrolling जो मैं यहाँ पुन: पेश करने का इरादा नहीं है :-)

मेरे पास उन्हें बेंचमार्क करने का धैर्य नहीं था, लेकिन मेरा मानना ​​है कि प्रतिबंधित संस्करण और तेज़ होगा।

सख्त अलियासिंग नियम

restrictकीवर्ड ही संगत प्रकार के संकेत दिए गए हैं (जैसे दो को प्रभावित करता है int*), क्योंकि सख्त अलियासिंग नियमों का कहना है कि असंगत प्रकार aliasing डिफ़ॉल्ट रूप से अपरिभाषित व्यवहार है, और इसलिए compilers मान सकते हैं यह हो और अनुकूलित नहीं करता दूर।

देखें: सख्त अलियासिंग नियम क्या है?

क्या यह संदर्भों के लिए काम करता है?

GCC डॉक्स के अनुसार यह करता है: https://gcc.gnu.org/oniltocs/gcc-5.1.0/gcc/Restricted-Pointers.html सिंटैक्स:

int &__restrict__ rref

thisसदस्य कार्यों के लिए एक संस्करण भी है :

void T::fn () __restrict__

अच्छा asnwer। क्या होगा यदि सख्त अलियासिंग अक्षम है -fno-strict-aliasing, तो restrictएक ही प्रकार या अलग-अलग प्रकार के पॉइंटर्स के बीच कोई अंतर नहीं करना चाहिए, नहीं? (मैं "प्रतिबंधित कीवर्ड केवल संगत प्रकारों के संकेत को प्रभावित करता है" का
उल्लेख कर रहा हूं

@ tobi303 मुझे नहीं पता! मुझे पता है अगर आप सुनिश्चित करने के लिए पता लगा ;-)
Ciro Santilli 冠状 find find find at at

@jww हाँ, यह इसे बेहतर बनाने का एक बेहतर तरीका है। अपडेट किया गया।
सिरो सेंटिल्ली 郝海东 冠状 iro 事件 法轮功 '

restrictC ++ में कुछ मतलब है। यदि आप restrictC ++ प्रोग्राम के मापदंडों के साथ C लाइब्रेरी फ़ंक्शन कहते हैं , तो आपको उस के निहितार्थों का पालन करना होगा। मूल रूप से, यदि restrictC लाइब्रेरी API में इसका उपयोग किया जाता है , तो इसका अर्थ है किसी को भी इसे किसी भी भाषा से कॉल करना, जिसमें Lisp से डायनेमिक FFI शामिल है।
काज

22

कुछ भी तो नहीं। इसे C99 मानक में जोड़ा गया था।


8
यह पूरी तरह सच नहीं है। जाहिरा तौर पर यह कुछ सी ++ कंपाइलरों द्वारा समर्थित है और कुछ लोग इसे उपलब्ध होने पर इसका उपयोग करने की जोरदार सलाह देते हैं, नीचे मेरा जवाब देखें।
रॉबर्ट एस। बार्न्स

18
@Robert एस बार्न्स: C ++ मानक restrictएक कीवर्ड के रूप में मान्यता नहीं देता है । इसलिए मेरा जवाब सही है। आप जो वर्णन करते हैं वह विशिष्ट व्यवहार और कुछ ऐसा है जो आपको वास्तव में भरोसा नहीं करना चाहिए
dirkgently

26
@dirkgently: पूरे सम्मान के साथ, क्यों नहीं? कई परियोजनाएं केवल विशिष्ट या बहुत कम संकलक द्वारा समर्थित विशिष्ट गैर-मानक भाषा एक्सटेंशन से जुड़ी होती हैं। लिनक्स कर्नेल और gcc का ध्यान आता है। किसी विशिष्ट संकलक के साथ चिपकना असामान्य नहीं है, या किसी परियोजना के संपूर्ण उपयोगी जीवनकाल के लिए एक विशिष्ट संकलक का एक विशिष्ट संशोधन भी है। प्रत्येक कार्यक्रम को सख्ती से अनुरूप बनाने की आवश्यकता नहीं है।
रॉबर्ट एस। बार्न्स

7
@ रॉबर्ट एस बार्न्स: मैं संभवतः किसी भी आगे तनाव नहीं कर सकता कि आपको कार्यान्वयन विशिष्ट व्यवहार पर निर्भर क्यों नहीं होना चाहिए। लिनक्स और जीसीसी के लिए - सोचें और आप देखेंगे कि वे आपके बचाव में एक अच्छा उदाहरण क्यों नहीं हैं। मैं अभी तक अपने जीवन भर के लिए एक संकलक संस्करण पर चलने वाले सॉफ्टवेयर के एक मामूली सफल टुकड़े को देख पा रहा हूं ।
dirkgently

16
@ रॉबर्ट एस। बार्न्स: प्रश्न ने कहा कि ++। MSVC नहीं, Gcc नहीं, AIX नहीं। यदि acidzombie24 संकलक विशिष्ट एक्सटेंशन चाहता था, तो उसे कहा / टैग किया जाना चाहिए था।
KitsuneYMG

12

यह कीवर्ड जोड़ने का मूल प्रस्ताव है। जैसा कि dirkgently बताया गया है, यह एक C99 फीचर है; इसका C ++ से कोई लेना-देना नहीं है।


5
कई C ++ कंपाइलर उस __restrict__कीवर्ड को सपोर्ट करते हैं जो मेरे द्वारा बताए गए समान है।
रॉबर्ट एस। बार्न्स

इसमें C ++ के साथ करने के लिए सब कुछ है, क्योंकि C ++ प्रोग्राम C लाइब्रेरीज़, और C लाइब्रेरीज़ का उपयोग करते हैं restrict। C ++ प्रोग्राम का व्यवहार अपरिभाषित हो जाता है यदि यह उसके द्वारा लगाए गए प्रतिबंधों का उल्लंघन करता है restrict
काज

@kaz पूरी तरह से गलत है। इसका C ++ से कोई लेना-देना नहीं है क्योंकि यह C ++ का कीवर्ड या फीचर नहीं है, और यदि आप C ++ में C हेडर फ़ाइलों का उपयोग करते हैं तो आपको restrictकीवर्ड को हटाना होगा । बेशक यदि आप एक सी फ़ंक्शन को अलियास किए गए पॉइंटर्स पास करते हैं जो उन्हें प्रतिबंधित घोषित करता है (जो आप सी ++ या सी से कर सकते हैं) तो यह अपरिभाषित है, लेकिन यह आप पर है।
जिम बाल्टर

@JimBalter मैं देख रहा हूं, इसलिए आप जो कह रहे हैं कि C ++ प्रोग्राम C लाइब्रेरी और C लाइब्रेरी का उपयोग करते हैं restrict। C ++ प्रोग्राम का व्यवहार अपरिभाषित हो जाता है यदि यह प्रतिबंधित द्वारा लगाए गए प्रतिबंधों का उल्लंघन करता है। लेकिन इसका वास्तव में C ++ से कोई लेना-देना नहीं है, क्योंकि यह "आप" पर है।
काज

5

C ++ में ऐसा कोई कीवर्ड नहीं है। C ++ कीवर्ड की सूची C ++ भाषा मानक के खंड 2.11 / 1 में पाई जा सकती है। restrictC भाषा में C99 संस्करण में एक खोजशब्द है और C ++ में नहीं है।


5
कई C ++ कंपाइलर उस __restrict__कीवर्ड को सपोर्ट करते हैं जो मेरे द्वारा बताए गए समान है।
रॉबर्ट एस। बार्न्स

17
@Robert: लेकिन C ++ में ऐसा कोई कीवर्ड नहीं है । व्यक्तिगत संकलक क्या करते हैं, उनका अपना व्यवसाय है, लेकिन यह C ++ भाषा का हिस्सा नहीं है।
जलफ

4

चूँकि कुछ C पुस्तकालयों की हेडर फ़ाइल कीवर्ड का उपयोग करती हैं, C ++ भाषा को इसके बारे में कुछ करना होगा .. कम से कम, कीवर्ड को अनदेखा करना, इसलिए हमें कीवर्ड को दबाने के लिए कीवर्ड को रिक्त मैक्रो में #define नहीं करना होगा ।


3
मुझे लगता है कि या तो एक extern Cघोषणा का उपयोग करके नियंत्रित किया जाएगा , या इसे चुपचाप गिरा दिया जाएगा, जैसा कि एआईसीसी सी / सी ++ संकलक के साथ होता है, जो इसके बजाय __rerstrict__कीवर्ड को संभालता है । उस कीवर्ड को gcc के तहत भी सपोर्ट किया गया है ताकि कोड उसी के नीचे g ++ में संकलित हो जाए।
रॉबर्ट एस। बार्न्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.