क्या अंतर है
int x=7;
तथा
register int x=7;
?
मैं C ++ का उपयोग कर रहा हूं।
क्या अंतर है
int x=7;
तथा
register int x=7;
?
मैं C ++ का उपयोग कर रहा हूं।
registerC और C ++ के बीच अलग - अलग शब्दार्थ होते हैं।
register int a[1];उस घोषणा के साथ, आप उस एरे को इंडेक्स नहीं कर सकते। यदि आप कोशिश करते हैं, तो आप UB
जवाबों:
C ++ में जैसा कि यह 2010 में अस्तित्व में था, कोई भी प्रोग्राम जो मान्य है जो "ऑटो" या "रजिस्टर" कीवर्ड का उपयोग करता है, शब्दार्थ निकाले गए उन कीवर्ड्स के साथ एक समान होगा (जब तक कि वे कड़े मैक्रो या अन्य समान संदर्भों में प्रकट नहीं होते)। इस अर्थ में, कीवर्ड ठीक से संकलित कार्यक्रमों के लिए बेकार हैं। दूसरी ओर, कीवर्ड कुछ मैक्रो संदर्भों में उपयोगी हो सकते हैं ताकि यह सुनिश्चित किया जा सके कि मैक्रो का अनुचित उपयोग बोगस कोड के निर्माण के बजाय एक संकलन-समय त्रुटि का कारण होगा।
C ++ 11 और भाषा के बाद के संस्करणों में, autoकीवर्ड को फिर से टाइप करने के लिए एक छद्म प्रकार की वस्तुओं के रूप में कार्य करने के लिए पुन: purposed किया गया था, जो एक संकलक स्वचालित रूप से प्रारंभिक अभिव्यक्ति के प्रकार के साथ बदल देगा। इस प्रकार, C ++ 03 में, घोषणा: एक ब्लॉक संदर्भ के भीतर उपयोग किए auto int i=(unsigned char)5;जाने के बराबर थी int i=5;और auto i=(unsigned char)5;एक बाधा उल्लंघन था। C ++ 11 में, auto int i=(unsigned char)5;एक बाधा उल्लंघन auto i=(unsigned char)5;बन गया जबकि इसके बराबर हो गया auto unsigned char i=5;।
autoको केवल छोड़ा नहीं जा सकता है ... शायद आप अपना उत्तर अपडेट कर सकते हैं।
registerहै और इसे ++ 17 के लिए हटाने का प्रस्ताव होने जा रहा है।
autoका उपयोग अब स्वचालित प्रकार की कटौती के लिए किया जाता है, लेकिन इससे पहले, यह निर्दिष्ट किया जाता था कि आप चाहते थे कि आपका चर "स्वचालित रूप से" संग्रहीत हो ( इसलिए स्टैक पर मेरा अनुमान है) कीवर्ड के विपरीत register(जिसका अर्थ है "प्रोसेसर का रजिस्टर"):
register संकलक के लिए एक संकेत है, यह सलाह देता है कि मेमोरी के बजाय एक प्रोसेसर रजिस्टर में उस चर को संग्रहीत करें (उदाहरण के लिए, स्टैक के बजाय)।
कंपाइलर उस संकेत का पालन कर सकता है या नहीं भी कर सकता है।
हर्ब सटर के अनुसार "कीवर्ड जो नहीं हैं (या, किसी अन्य नाम से टिप्पणियां)" :
एक रजिस्टर विनिर्देशक के पास ऑटो स्पेसियर के समान शब्दार्थ है ...
storage-class-specifierव्याकरण में नहीं है और इसमें कोई परिभाषित शब्दार्थ नहीं है। एक अनुरूप संकलक एक त्रुटि फेंक सकता है जैसे कि क्लैंग करता है। बहरहाल, कुछ कार्यान्वयन अभी भी इसकी अनुमति देते हैं और या तो इसे (MSVC, ICC) अनदेखा करते हैं या इसे अनुकूलन संकेत (GCC) के रूप में उपयोग करते हैं। Open-std.org/jtc1/sc22/wg21/docs/papers/2015/p000151.html देखें । मैंने एक बिंदु पर मिसकैप किया था: इसे C ++ 11 में हटा दिया गया था।
हर्ब सटर के अनुसार , register" व्हॉट्सएप के समान अर्थपूर्ण है " और C ++ प्रोग्राम के शब्दार्थ पर कोई प्रभाव नहीं पड़ता है।
लगभग निश्चित रूप से कुछ भी नहीं।
registerसंकलक को संकेत है कि आप xबहुत उपयोग करके योजना बनाते हैं , और आपको लगता है कि इसे एक रजिस्टर में रखा जाना चाहिए।
हालांकि, कंपाइलर अब यह निर्धारित करने में बहुत बेहतर हैं कि औसत (या यहां तक कि विशेषज्ञ) प्रोग्रामर की तुलना में रजिस्टरों में कौन से मूल्यों को रखा जाना चाहिए, इसलिए कंपाइलर केवल कीवर्ड को अनदेखा करते हैं, और वे जो चाहते हैं वह करते हैं।
registerC ++ 11 में पदावनत किया गया है। यह अप्रयुक्त और C ++ 17 में आरक्षित है।
registerकीवर्ड के लिए उपयोगी था:
एक उत्पादक प्रणाली का एक उदाहरण, जहाँ registerकीवर्ड की आवश्यकता थी:
typedef unsigned long long Out;
volatile Out out,tmp;
Out register rax asm("rax");
asm volatile("rdtsc":"=A"(rax));
out=out*tmp+rax;
यह C ++ 11 के बाद से हटा दिया गया है और अप्रयुक्त और C ++ 17 में आरक्षित है ।
registerस्टोरेज क्लास स्पेसियर से अलग है और अभी भी जीसीसी द्वारा समर्थित है।
एक मामले पर विचार करें जब कंपाइलर के ऑप्टिमाइज़र के दो चर होते हैं और स्टैक पर एक को फैलाने के लिए मजबूर किया जाता है। ऐसा हुआ कि दोनों चरों का कंपाइलर का वजन समान है। यह देखते हुए कि कोई अंतर नहीं है, संकलक मनमाने ढंग से चर में से एक को फैला देगा। दूसरी ओर, registerकीवर्ड कंपाइलर को संकेत देता है कि कौन सा चर अधिक बार एक्सेस किया जाएगा। यह x86 प्रीफ़ैच इंस्ट्रक्शन के समान है, लेकिन कंपाइलर ऑप्टिमाइज़र के लिए।
स्पष्ट रूप से registerसंकेत उपयोगकर्ता द्वारा प्रदान की जाने वाली शाखा संभावना संकेत के समान हैं, और इन संभाव्यता संकेतों से अनुमान लगाया जा सकता है। यदि कंपाइलर जानता है कि कुछ शाखा अक्सर ली जाती है, तो यह रजिस्टरों में शाखा से संबंधित चर रखेगा। इसलिए मैं सुझाव देता हूं कि शाखा के संकेतों के बारे में अधिक देखभाल करें, और इसके बारे में भूल जाएं register। आदर्श रूप से आपके प्रोफाइलर को कंपाइलर के साथ किसी तरह संवाद करना चाहिए और आपको ऐसी बारीकियों के बारे में सोचने से भी रोकना चाहिए।
9.3 gcc के रूप में, संकलन का उपयोग करते हुए -std=c++2a, register एक संकलक चेतावनी का उत्पादन करता है, लेकिन इसका अभी भी वांछित प्रभाव है और इस उत्तर registerके संबंध में -O1-टोस्ट ऑप्टिमाइज़िंग फ़्लैग का संकलन करते समय C के लिए पहचान योग्य व्यवहार करता है । हालांकि clang ++ - 7 का उपयोग करना एक संकलक त्रुटि का कारण बनता है। तो हाँ, अनुकूलन केवल बिना अनुकूलन -O झंडे के साथ मानक संकलन पर फर्क करते हैं, लेकिन वे बुनियादी अनुकूलन हैं कि संकलक -O1 के साथ भी पता लगाएगा।register
अंतर केवल इतना है कि C ++ में, आपको रजिस्टर वैरिएबल का पता लेने की अनुमति है, जिसका अर्थ है कि अनुकूलन केवल तब होता है जब आप वैरिएबल या उसके उपनाम (सूचक बनाने के लिए) का संदर्भ नहीं लेते हैं या संदर्भ लेते हैं इसे कोड में (केवल - O0 पर, क्योंकि एक संदर्भ में भी एक पता है, क्योंकि यह स्टैक पर एक कास्ट पॉइंटर है , जो एक सूचक की तरह स्टैक से ऑप्टिमाइज़ किया जा सकता है अगर -OIFT का उपयोग करते हुए, सिवाय इसके कि वे कभी दिखाई नहीं देंगे स्टैक का उपयोग करके -OIFT, क्योंकि एक पॉइंटर के विपरीत, उन्हें नहीं बनाया जा सकता है volatileऔर उनके पते नहीं लिए जा सकते हैं), अन्यथा यह ऐसा व्यवहार करेगा जैसे आपने उपयोग नहीं किया था register, और मूल्य स्टैक पर संग्रहीत किया जाएगा।
-ओ0 पर, एक और अंतर यह है कि const registergcc C और gcc C ++ पर समान व्यवहार नहीं करते हैं। Gcc C पर, const registerव्यवहार करता है register, क्योंकि ब्लॉक-स्कोप constgcc पर अनुकूलित नहीं हैं। क्लैंग सी पर, registerकुछ भी नहीं होता है और केवल constब्लॉक-स्कोप ऑप्टिमाइज़ेशन लागू होते हैं। जीसीसी सी पर, registerअनुकूलन लागू होते हैं लेकिन constब्लॉक-स्कोप में कोई अनुकूलन नहीं है। सीसीसी सी ++ पर, दोनों registerऔर constब्लॉक-स्कोप ऑप्टिमाइज़ेशन गठबंधन करते हैं।
#include <stdio.h> //yes it's C code on C++
int main(void) {
const register int i = 3;
printf("%d", i);
return 0;
}
int i = 3;:
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 3
mov eax, DWORD PTR [rbp-4]
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
register int i = 3;:
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
push rbx
sub rsp, 8
mov ebx, 3
mov esi, ebx
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
mov rbx, QWORD PTR [rbp-8] //callee restoration
leave
ret
const int i = 3;
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 3 //still saves to stack
mov esi, 3 //immediate substitution
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
const register int i = 3;
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
mov esi, 3 //loads straight into esi saving rbx push/pop and extra indirection (because C++ block-scope const is always substituted immediately into the instruction)
mov edi, OFFSET FLAT:.LC0 // can't optimise away because printf only takes const char*
mov eax, 0 //zeroed: https://stackoverflow.com/a/6212755/7194773
call printf
mov eax, 0 //default return value of main is 0
pop rbp //nothing else pushed to stack -- more efficient than leave (rsp == rbp already)
ret
registerकंपाइलर को 1) बताता है कि इस मामले में एक स्थानीय चर को कैलेली में सहेजा गया है rbx, और 2) ऑप्टिमाइज़ आउट स्टैक लिखते हैं यदि वैरिएबल का पता कभी नहीं लिया गया है । constसंकलक को तुरंत मान बदलने के लिए कहता है (बजाय इसे रजिस्टर या मेमोरी से लोड करने के) और स्थानीय चर को डिफ़ॉल्ट व्यवहार के रूप में लिखने के लिए। const registerइन उभरे हुए अनुकूलन का संयोजन है। यह जितना पतला होता है उतना ही मिलता है।
इसके अलावा, सीसीसी और सी ++ registerपर , अपने दम पर, स्टैक पर पहले स्थानीय के लिए स्टैक पर एक यादृच्छिक 16 बाइट गैप बनाने के लिए लगता है , जिसके साथ ऐसा नहीं होता है const register।
का उपयोग कर संकलन - हालांकि, आगे; register0 अनुकूलन प्रभाव है क्योंकि अगर इसे रजिस्टर में रखा जा सकता है या तत्काल बनाया जा सकता है, तो यह हमेशा रहेगा और यदि यह नहीं होगा तो यह नहीं होगा; constअभी भी C और C ++ पर लोड का अनुकूलन करता है लेकिन केवल फ़ाइल स्कोप पर ; volatileअभी भी मानों को स्टैक से संग्रहीत और लोड करने के लिए मजबूर करता है।
.LC0:
.string "%d"
main:
//optimises out push and change of rbp
sub rsp, 8 //https://stackoverflow.com/a/40344912/7194773
mov esi, 3
mov edi, OFFSET FLAT:.LC0
xor eax, eax //xor 2 bytes vs 5 for mov eax, 0
call printf
xor eax, eax
add rsp, 8
ret