C ++ में कीवर्ड रजिस्टर करें


88

क्या अंतर है

int x=7;

तथा

register int x=7;

?

मैं C ++ का उपयोग कर रहा हूं।


8
@ गण: एएनएसआई सी एक रजिस्टर ऑब्जेक्ट का पता लेने की अनुमति नहीं देता है; यह प्रतिबंध
ब्रायन आर। बॉडी

1
@ ब्रायन: एचएम, आप सही कह रहे हैं। यह अब केवल एक नोट में है (यदि यह पता चलेगा कि शायद इसे नजरअंदाज कर दिया जाएगा), लेकिन अनिवार्य नहीं। जानकार अच्छा लगा। (खैर, की तरह: पी)
GManNickG

8
पुन: खोलने के लिए वोटिंग में registerC और C ++ के बीच अलग - अलग शब्दार्थ होते हैं।
सीबी बेली

3
इसके परिणामस्वरूप, C में एक सरणी रजिस्टर बनाकर सरणी-से-पॉइंटर रूपांतरण को मना करना संभव है: register int a[1];उस घोषणा के साथ, आप उस एरे को इंडेक्स नहीं कर सकते। यदि आप कोशिश करते हैं, तो आप UB
जोहान्स शबाब - litb

2
वास्तव में, मैंने पुनः खोलने के लिए मतदान किया। मैंने यह जानने के लिए मतदान किया कि क्या अंतर है।
GManNickG

जवाबों:


24

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;


22
अंतिम बिट का एक उदाहरण उपयोगी हो सकता है।
डेनिस ज़िकेफोज

14
यह उत्तर अब सही नहीं है, 2011 के बाद से, कीवर्ड autoको केवल छोड़ा नहीं जा सकता है ... शायद आप अपना उत्तर अपडेट कर सकते हैं।
वाल्टर

2
@Walter: क्या आप बदल सकते हैं जो बदल गया है? मैंने सभी भाषा परिवर्तनों का पालन नहीं किया है।
सुपरैट

2
@supercat, हाँ, फिलहाल, लेकिन अपदस्थ registerहै और इसे ++ 17 के लिए हटाने का प्रस्ताव होने जा रहा है।
जोनाथन वैक्ली

3
En.cppreference.com/w/cpp/language/auto के अनुसार , पोस्ट C ++ 11, autoका उपयोग अब स्वचालित प्रकार की कटौती के लिए किया जाता है, लेकिन इससे पहले, यह निर्दिष्ट किया जाता था कि आप चाहते थे कि आपका चर "स्वचालित रूप से" संग्रहीत हो ( इसलिए स्टैक पर मेरा अनुमान है) कीवर्ड के विपरीत register(जिसका अर्थ है "प्रोसेसर का रजिस्टर"):
गिलोयूम

96

register संकलक के लिए एक संकेत है, यह सलाह देता है कि मेमोरी के बजाय एक प्रोसेसर रजिस्टर में उस चर को संग्रहीत करें (उदाहरण के लिए, स्टैक के बजाय)।

कंपाइलर उस संकेत का पालन कर सकता है या नहीं भी कर सकता है।

हर्ब सटर के अनुसार "कीवर्ड जो नहीं हैं (या, किसी अन्य नाम से टिप्पणियां)" :

एक रजिस्टर विनिर्देशक के पास ऑटो स्पेसियर के समान शब्दार्थ है ...


2
C ++ 17 के बाद से, यह पदावनत, अप्रयुक्त और आरक्षित है, हालांकि।
ZachB

@ZachB, यह गलत है; रजिस्टर सी ++ 17 में आरक्षित है लेकिन यह अभी भी काम करता है और सी के रजिस्टर में लगभग समान रूप से कार्य करता है
लुईस केल्सी

@LewisKelsey यह अप्रयुक्त और सी ++ 17 कल्पना में आरक्षित है; यह storage-class-specifierव्याकरण में नहीं है और इसमें कोई परिभाषित शब्दार्थ नहीं है। एक अनुरूप संकलक एक त्रुटि फेंक सकता है जैसे कि क्लैंग करता है। बहरहाल, कुछ कार्यान्वयन अभी भी इसकी अनुमति देते हैं और या तो इसे (MSVC, ICC) अनदेखा करते हैं या इसे अनुकूलन संकेत (GCC) के रूप में उपयोग करते हैं। Open-std.org/jtc1/sc22/wg21/docs/papers/2015/p000151.html देखें । मैंने एक बिंदु पर मिसकैप किया था: इसे C ++ 11 में हटा दिया गया था।
ZachB


25

आज के संकलक के साथ, शायद कुछ भी नहीं। तेजी से पहुंच के लिए एक रजिस्टर में एक चर रखने के लिए orginally एक संकेत था, लेकिन अधिकांश संकलक आज उस संकेत को अनदेखा करते हैं और खुद के लिए निर्णय लेते हैं।


9

लगभग निश्चित रूप से कुछ भी नहीं।

registerसंकलक को संकेत है कि आप xबहुत उपयोग करके योजना बनाते हैं , और आपको लगता है कि इसे एक रजिस्टर में रखा जाना चाहिए।

हालांकि, कंपाइलर अब यह निर्धारित करने में बहुत बेहतर हैं कि औसत (या यहां तक ​​कि विशेषज्ञ) प्रोग्रामर की तुलना में रजिस्टरों में कौन से मूल्यों को रखा जाना चाहिए, इसलिए कंपाइलर केवल कीवर्ड को अनदेखा करते हैं, और वे जो चाहते हैं वह करते हैं।



7

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 में आरक्षित है ।


2
और मैं जोड़ूंगा कि 'रजिस्टर' कीवर्ड केवल एक माइक्रोकंट्रोलर पर उपयोगी होगा जो बिना थ्रेड और मल्टी टास्किंग के एकल सी ++ प्रोग्राम चला रहा है। C ++ प्रोग्राम को यह सुनिश्चित करने के लिए पूरे CPU का मालिक होना चाहिए कि 'रजिस्टर' वेरिएबल को विशेष CPU रजिस्टरों से स्थानांतरित नहीं किया जाएगा।
सैंटियागो विलाफुर्ते

@SantiagoVillafuerte क्या आप इसे उत्तर का संपादन जोड़ना चाहते हैं?
n कंप्यूटर्स

मैं अपने उत्तर के बारे में निश्चित नहीं हूँ ... हालाँकि यह प्रशंसनीय लगता है। मैं इसे एक टिप्पणी के रूप में छोड़ना चाहूंगा ताकि अन्य इसे स्वीकार करें या इसे अस्वीकृत कर दें।
सांतियागो विलाफुर्ते

1
@SantiagoVillafuerte यह वास्तव में सच नहीं है, मल्टीटास्किंग सिस्टम में जब संदर्भ ओएस को स्विच करता है - एप्लिकेशन नहीं - रजिस्टर को बचाने / बहाल करने के लिए जिम्मेदार है। चूंकि आप हर सीपीयू निर्देश के बाद स्विचन के संदर्भ में नहीं हैं, इसलिए रजिस्टरों में चीजों को डालना बिल्कुल सार्थक है। यहां अन्य उत्तर (जो संकलक आपकी राय के बारे में परवाह नहीं करते हैं जब यह आवंटन को पंजीकृत करने की बात आती है) अधिक सटीक हैं।
घन

आपने जो उदाहरण दिखाया है वह वास्तव में जीसीसी के एक्सप्लोसिव रजिस्टर वेरिएबल्स एक्सटेंशन का उपयोग कर रहा है , जो registerस्टोरेज क्लास स्पेसियर से अलग है और अभी भी जीसीसी द्वारा समर्थित है।
ZachB

1

एक मामले पर विचार करें जब कंपाइलर के ऑप्टिमाइज़र के दो चर होते हैं और स्टैक पर एक को फैलाने के लिए मजबूर किया जाता है। ऐसा हुआ कि दोनों चरों का कंपाइलर का वजन समान है। यह देखते हुए कि कोई अंतर नहीं है, संकलक मनमाने ढंग से चर में से एक को फैला देगा। दूसरी ओर, registerकीवर्ड कंपाइलर को संकेत देता है कि कौन सा चर अधिक बार एक्सेस किया जाएगा। यह x86 प्रीफ़ैच इंस्ट्रक्शन के समान है, लेकिन कंपाइलर ऑप्टिमाइज़र के लिए।

स्पष्ट रूप से registerसंकेत उपयोगकर्ता द्वारा प्रदान की जाने वाली शाखा संभावना संकेत के समान हैं, और इन संभाव्यता संकेतों से अनुमान लगाया जा सकता है। यदि कंपाइलर जानता है कि कुछ शाखा अक्सर ली जाती है, तो यह रजिस्टरों में शाखा से संबंधित चर रखेगा। इसलिए मैं सुझाव देता हूं कि शाखा के संकेतों के बारे में अधिक देखभाल करें, और इसके बारे में भूल जाएं register। आदर्श रूप से आपके प्रोफाइलर को कंपाइलर के साथ किसी तरह संवाद करना चाहिए और आपको ऐसी बारीकियों के बारे में सोचने से भी रोकना चाहिए।


1

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