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


272

registerC भाषा में कीवर्ड क्या करता है ? मैंने पढ़ा है कि इसका उपयोग अनुकूलन के लिए किया जाता है लेकिन किसी भी मानक में स्पष्ट रूप से परिभाषित नहीं है। क्या यह अभी भी प्रासंगिक है और यदि हां, तो आप इसका उपयोग कब करेंगे?


41
C में रजिस्टर कीवर्ड क्या करता है? नजरअंदाज कर दिया जाता है :)
सर्वश्रेष्ठ bestss

18
@bestsss पूरी तरह से नजरअंदाज नहीं किया। registerचर का पता प्राप्त करने का प्रयास करें ।
११:

4
वह कोड जो आप पढ़ रहे हैं, वह पुराना है youtube.com/watch?v=ibF36Yyeehw#t=1827
कर्नल पैनिक

जवाबों:


340

यह संकलक को संकेत देता है कि चर का भारी उपयोग किया जाएगा और आप इसे संभव होने पर प्रोसेसर रजिस्टर में रखने की सलाह देते हैं।

अधिकांश आधुनिक कंपाइलर स्वचालित रूप से ऐसा करते हैं, और हमें मनुष्यों की तुलना में उन्हें लेने में बेहतर होते हैं।


17
खैर, मैंने अपने एसीएम प्रस्तुतियाँ प्राप्त करने के लिए रजिस्टर के साथ प्रयोग किया, और कभी-कभी यह वास्तव में मदद करता है। लेकिन आपको वास्तव में सावधान रहना होगा, क्योंकि खराब विकल्प प्रदर्शन को कम करते हैं।
ypnos

80
'रजिस्टर' का उपयोग नहीं करने का एक अच्छा कारण : आप एक वेरिएबल घोषित 'रजिस्टर' का पता नहीं लगा सकते हैं
एडम रोसेनफील्ड

22
ध्यान दें कि कुछ / कई कंपाइलर रजिस्टर कीवर्ड (जो पूरी तरह से कानूनी है) को पूरी तरह से नजरअंदाज कर देंगे।
यूरो माइकेल

4
ypnos: वास्तव में ACM ICPC समस्याओं के लिए एक समाधान की गति इस तरह के सूक्ष्म-अनुकूलन पर एल्गोरिथ्म विकल्प पर बहुत अधिक निर्भर करती है। 5-सेकंड की समय सीमा आमतौर पर एक सही समाधान के लिए पर्याप्त है, खासकर जब जावा के बजाय सी का उपयोग करते हैं।
जॉय

65
@ पूर्व: आप शायद यह जानते हैं, लेकिन सिर्फ स्पष्ट होने के लिए, एक registerचर के पते को रोकने के लिए संकलक की आवश्यकता होती है ; यह कीवर्ड का एकमात्र अनिवार्य प्रभाव है register। यहां तक ​​कि यह अनुकूलन को बेहतर बनाने के लिए पर्याप्त है, क्योंकि यह बताने के लिए तुच्छ हो जाता है कि चर केवल इस फ़ंक्शन के भीतर संशोधित किया जा सकता है।
डेल हाग्लगंड

69

मुझे आश्चर्य है कि किसी ने भी उल्लेख नहीं किया कि आप रजिस्टर चर का पता नहीं ले सकते, भले ही संकलक रजिस्टर में स्मृति के बजाय चर रखने का फैसला करता है।

इसलिए registerआप कुछ भी नहीं जीतते हैं (वैसे भी कंपाइलर खुद तय करेगा कि वेरिएबल को कहां रखा जाए) और &ऑपरेटर को खो दें - इसका उपयोग करने का कोई कारण नहीं।


94
वास्तव में एक कारण है। मात्र तथ्य यह है कि आप चर का एक पता नहीं ले सकते हैं कुछ अनुकूलन के अवसर देता है: संकलक यह साबित कर सकता है कि चर को बदल नहीं दिया जाएगा।
अलेक्जेंड्रे सी।

8
संकलक यह साबित करने में बेहद भयानक हैं कि उपद्रव के मामले में नहीं होते हैं, इसलिए इसके registerलिए उपयोगी है, भले ही संकलक इसे एक रजिस्टर में न रखे।
माइल्स राउत

2
@AlexandreC, माइल्स, कंपाइलर यह जाँचने में पूरी तरह से ठीक हैं कि कहीं एक वैरिएबल लिया गया है या नहीं। तो अलियासिंग का पता लगाने के बारे में अन्य कठिनाइयों की परवाह किए बिना, आराम करना जो आपको कुछ नहीं खरीदता है। जब K + R ने पहली बार C बनाया था, तो यह वास्तव में अग्रिम रूप से जानना उपयोगी था कि & का उपयोग नहीं किया जाएगा, क्योंकि उस संकलक ने वास्तव में घोषणा को देखते हुए रजिस्टर आवंटन निर्णय लिया था, निम्नलिखित कोड को देखने से पहले। इसीलिए निषेधाज्ञा लागू है। 'रजिस्टर' कीवर्ड अनिवार्य रूप से अब अप्रचलित है।
greggo

25
इस तर्क constसे भी बेकार है क्योंकि यह आपको कुछ भी नहीं जीतता है, आप केवल एक चर को बदलने की क्षमता ढीली करते हैं। registerयह सुनिश्चित करने के लिए इस्तेमाल किया जा सकता है कि कोई बिना सोचे-समझे भविष्य में किसी चर का पता न लगा ले। मेरे पास registerहालांकि उपयोग करने का कभी कारण नहीं था ।
टोर क्लिंगबर्ग

34

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


8
C ++ का उपयोग करने वाले लोगों के लिए वर्थ जोड़ने से, C ++ आपको एक रजिस्टर चर का पता लेने
देगा

5
@Will: ... लेकिन कंपाइलर के परिणामस्वरूप कीवर्ड की अनदेखी करने की संभावना खत्म हो जाएगी। मेरा जवाब देखिए।
bwDraco

हां, ऐसा लगता है कि 'रजिस्टर' सी ++ में एक प्लेसबो है, यह सिर्फ सी कोड को सी ++ के रूप में संकलित करने की अनुमति देने के लिए है। और इसे संदर्भ, या कॉन्स्टेंस-रेफरेंस द्वारा पास करने की अनुमति देने के दौरान और वर्जित करने के लिए बहुत अधिक समझ में नहीं आता है, और बिना पास-रेफरेंस के आपने सी ++ को गंभीरता से तोड़ा है।
greggo

22

मुझे पता है कि यह प्रश्न C के बारे में है, लेकिन C ++ के लिए यही प्रश्न इस प्रश्न के सटीक डुप्लिकेट के रूप में बंद किया गया था। यह उत्तर इसलिए C के लिए लागू नहीं हो सकता है।


सी ++ 11 मानक का नवीनतम मसौदा, एन 3485 , 7.1.1 / 3 में यह कहता है:

एक registerविनिर्देश कार्यान्वयन के लिए एक संकेत है कि घोषित चर इतना भारी उपयोग किया जाएगा। [ नोट: संकेत को नजरअंदाज किया जा सकता है और ज्यादातर कार्यान्वयन में इसे अनदेखा किया जाएगा यदि चर का पता लिया जाता है। यह उपयोग पदावनत है ... - ध्यान दें ]

सी ++ में (लेकिन सी में नहीं ), मानक यह नहीं बताता है कि आप घोषित चर का पता नहीं ले सकते हैं register; हालाँकि, क्योंकि पूरे जीवनकाल में सीपीयू रजिस्टर में संग्रहित एक चर में इसके साथ कोई स्मृति स्थान नहीं जुड़ा होता है, इसलिए इसका पता लेने का प्रयास अमान्य होगा, और संकलक registerकीवर्ड को पता लेने की अनुमति देने की उपेक्षा करेगा ।


17

यह कम से कम 15 वर्षों के लिए प्रासंगिक नहीं है क्योंकि ऑप्टिमाइज़र इस बारे में बेहतर निर्णय लेते हैं कि आप जितना कर सकते हैं। प्रासंगिक होने के बावजूद, इसने बहुत सारे रजिस्टर के साथ सीपीयू आर्किटेक्चर पर बहुत अधिक अर्थ लगाया, जैसे SPARC या M68000 ने इंटेल पर रजिस्टर की अपनी शुद्धता के साथ किया था, जिनमें से अधिकांश अपने स्वयं के प्रयोजनों के लिए संकलक द्वारा आरक्षित हैं।


13

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

विभिन्न परिस्थितियों में आधुनिक संकलक द्वारा इसका फायदा उठाया जा सकता है, और जटिल कोड में संकलक की थोड़ी बहुत मदद कर सकता है - सरल कोड में संकलक यह पता लगा सकते हैं।

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


"संकलक बताता है .." नहीं, यह नहीं है। सभी ऑटो चर में वह संपत्ति होती है, जब तक कि आप उसका पता नहीं लेते हैं और इसका उपयोग उन तरीकों से करते हैं जो कुछ विशेष विश्लेषण योग्य उपयोगों से अधिक है। इसलिए, संकलक इसे कोड से जानता है, भले ही आप रजिस्टर कीवर्ड का उपयोग करें। ऐसा होता है कि 'रजिस्टर' कीवर्ड इस तरह के निर्माण को लिखने के लिए अवैध बनाता है, लेकिन यदि आप कीवर्ड का उपयोग नहीं करते हैं, और ही इस तरह से पता नहीं लेते हैं, तो कंपाइलर अभी भी जानता है कि यह सुरक्षित है। ऐसी जानकारी अनुकूलन के लिए महत्वपूर्ण है।
greggo

1
@greggo: बहुत बुरा registerसब पर पता लेने, अन्यथा बाद से यह compilers मामलों में जहां एक संकलक रजिस्टर अनुकूलन लागू करने में सक्षम होगा की यह बताने के लिए उपयोगी हो सकता है मना करता है के बावजूद एक चर के पते एक बाहरी कार्य करने के लिए पारित किया जा रहा (चर करने के लिए होगा उस विशेष कॉल के लिए मेमोरी में फ्लश किया जा सकता है , लेकिन एक बार फ़ंक्शन वापस आने के बाद, कंपाइलर इसे फिर से एक चर के रूप में मान सकता है जिसका पता कभी नहीं लिया गया था)।
सुपरकैट

@ मुझे लगता है कि कंपाइलर के साथ बातचीत करने के लिए अभी भी बहुत मुश्किल बातचीत होगी। यदि वह वह है जो आप संकलक को बताना चाहते हैं, तो आप इसे पहले चर को दूसरे पर कॉपी करके कर सकते हैं, जिस पर 'और' नहीं है, और फिर पहले वाले का उपयोग कभी नहीं करना चाहिए।
०१:३

1
@greggo: कह रही है कि अगर barएक है registerचर, एक संकलक अपने खाली समय में हो सकता है की जगह foo(&bar);के साथ int temp=bar; foo(&temp); bar=temp;, लेकिन का पता लेने के barसबसे अन्य संदर्भों में मना किया जाएगा वाले अत्यंत जटिल नियम की तरह लग नहीं होता। यदि चर को अन्यथा रजिस्टर में रखा जा सकता है, तो प्रतिस्थापन कोड को छोटा बना देगा। अगर चर को रैम में रखने की आवश्यकता होगी, तो प्रतिस्थापन कोड को बड़ा बना देगा। संकलक तक प्रतिस्थापन बनाने के सवाल को छोड़कर, दोनों मामलों में बेहतर कोड होगा।
सुपरकैट

1
@ वर्ण: registerवैश्विक चर पर एक योग्यता की अनुमति , चाहे संकलक पते को ले जाने की अनुमति देता है या नहीं, उन मामलों में कुछ अच्छा अनुकूलन की अनुमति देगा जहां एक वैश्विक चर का उपयोग करने वाले एक अंतर्निर्मित फ़ंक्शन को लूप में बार-बार कहा जाता है। मैं उस चर को लूप पुनरावृत्तियों के बीच रजिस्टर में रखने के लिए किसी अन्य तरीके के बारे में नहीं सोच सकता - क्या आप कर सकते हैं?
सुपरकैट

13

मैंने पढ़ा है कि इसका उपयोग अनुकूलन के लिए किया जाता है लेकिन किसी भी मानक में स्पष्ट रूप से परिभाषित नहीं है।

वास्तव में यह है स्पष्ट रूप से सी मानक द्वारा परिभाषित। N1570 ड्राफ्ट सेक्शन 6.7.1 पैरा 6 का हवाला देते हुए (अन्य संस्करणों में एक ही शब्द है):

स्टोरेज-क्लास स्पेसियर के साथ एक ऑब्जेक्ट के लिए एक पहचानकर्ता की घोषणा से registerपता चलता है कि ऑब्जेक्ट तक पहुंच जितनी जल्दी हो सके। इस तरह के सुझाव किस हद तक प्रभावी हैं, कार्यान्वयन-परिभाषित है।

यूनिरी &ऑपरेटर के साथ परिभाषित ऑब्जेक्ट पर लागू नहीं किया जा सकता है register, और registerबाहरी घोषणा में उपयोग नहीं किया जा सकता है।

कुछ अन्य (काफी अस्पष्ट) नियम हैं जो विशिष्ट- registerयोग्य वस्तुओं के लिए हैं:

  • किसी सरणी ऑब्जेक्ट को परिभाषित करने के साथ registerअपरिभाषित व्यवहार होता है।
    सुधार: यह एक सरणी ऑब्जेक्ट को परिभाषित करने के लिए कानूनी है register, लेकिन आप ऐसी ऑब्जेक्ट के साथ कुछ भी उपयोगी नहीं कर सकते हैं (किसी सरणी में अनुक्रमण इसके प्रारंभिक तत्व का पता लेने के लिए आवश्यक है)।
  • _Alignasविनिर्देशक (सी 11 में नया) इस तरह के एक वस्तु को लागू नहीं किया जा सकता है।
  • यदि va_startमैक्रो को दिया गया पैरामीटर नाम- registerयोग्य है, तो व्यवहार अपरिभाषित है।

कुछ अन्य हो सकते हैं; यदि आप रुचि रखते हैं तो मानक का एक प्रारूप डाउनलोड करें और "रजिस्टर" खोजें।

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

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


इसलिए इस कार्यक्रम का व्यवहार सी मानक के अनुसार वास्तव में अपरिभाषित है? क्या यह C ++ में अच्छी तरह से परिभाषित है? मुझे लगता है कि यह C ++ में अच्छी तरह से परिभाषित है।
विध्वंसक

@ डस्टर: यह अपरिभाषित क्यों होगा? registerअगर आप क्या सोच रहे हैं, तो वहाँ -क्वालिफ़ाइड ऐरे ऑब्जेक्ट नहीं है ।
कीथ थॉम्पसन

माफ करना, मैं मुख्य () में ऐलान घोषणा में रजिस्टर कीवर्ड लिखना भूल गया। क्या यह C ++ में अच्छी तरह से परिभाषित है?
विध्वंसक

मैं registerसरणी वस्तुओं को परिभाषित करने के बारे में गलत था ; मेरे उत्तर में अपडेट की गई पहली गोली बिंदु देखें। इस तरह की वस्तु को परिभाषित करना कानूनी है, लेकिन आप इसके साथ कुछ नहीं कर सकते। जोड़ते हैं registerकी परिभाषा के लिए sमें अपने उदाहरण , कार्यक्रम (एक बाधा उल्लंघन) अवैध सी सी ++ में पर एक ही प्रतिबन्ध नहीं लगा है register, इसलिए कार्यक्रम वैध सी होगा ++ (लेकिन का उपयोग कर registerव्यर्थ हो जाएगा)।
कीथ थॉम्पसन

@KeithThompson: registerकीवर्ड एक उपयोगी उद्देश्य की पूर्ति कर सकता है यदि वह ऐसे वैरिएबल का पता लेने के लिए कानूनी हो, लेकिन केवल ऐसे मामलों में जहां शब्दार्थक को उस प्रति को अस्थायी रूप से कॉपी करके अप्रभावित किया जाएगा जब उसका पता लिया जाता है, और इसे अस्थायी से पुनः लोड किया जा रहा है। अगले अनुक्रम बिंदु पर। यह संकलक को यह मानने की अनुमति देगा कि चर को सभी पॉइंटर एक्सेस के पार एक रजिस्टर में सुरक्षित रूप से रखा जा सकता है बशर्ते कि इसका पता किसी भी स्थान पर लगा हो।
सुपरकैट

9

कहानी का समय!

सी, एक भाषा के रूप में, कंप्यूटर का एक अमूर्त हिस्सा है। यह आपको चीजों को करने की अनुमति देता है, जो एक कंप्यूटर करता है, जो कि मेमोरी में हेरफेर करता है, गणित करता है, चीजों को प्रिंट करता है, आदि।

लेकिन C केवल एक अमूर्त है। और अंत में, यह जो आप से निकाल रहा है वह विधानसभा भाषा है। असेंबली वह भाषा है जिसे सीपीयू पढ़ता है, और यदि आप इसका उपयोग करते हैं, तो आप सीपीयू के संदर्भ में काम करते हैं। सीपीयू क्या करता है? मूल रूप से, यह मेमोरी से पढ़ता है, गणित करता है, और मेमोरी में लिखता है। सीपीयू स्मृति में संख्याओं पर केवल गणित नहीं करता है। सबसे पहले, आपको सीपीयू के अंदर मेमोरी से मेमोरी तक एक नंबर को स्थानांतरित करना होगा जिसे एक रजिस्टर कहा जाता है। एक बार जब आप इस नंबर पर करने की आवश्यकता होती है, तो आप इसे सामान्य सिस्टम मेमोरी में वापस ले जा सकते हैं। सिस्टम मेमोरी का उपयोग क्यों करें? रजिस्टर संख्या में सीमित हैं। आप केवल आधुनिक प्रोसेसर में लगभग सौ बाइट्स प्राप्त करते हैं, और पुराने लोकप्रिय प्रोसेसर और भी अधिक काल्पनिक रूप से सीमित थे (6502 में आपके मुफ्त उपयोग के लिए 3 8-बिट रजिस्टर थे)। तो, आपका औसत गणित ऑपरेशन जैसा दिखता है:

load first number from memory
load second number from memory
add the two
store answer into memory

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

जब आप एक चर घोषित करते हैं register, आप कंपाइलर को बता रहे हैं "यो, मैं इस वैरिएबल को बहुत इस्तेमाल करने और / या कम रहने का इरादा रखता हूं। अगर मैं होता तो मैं इसे रजिस्टर में रखने की कोशिश करता।" जब C मानक कहता है कि कंपाइलरों को वास्तव में कुछ भी नहीं करना है, ऐसा इसलिए है क्योंकि C मानक को नहीं पता है कि आप किस कंप्यूटर के लिए संकलन कर रहे हैं, और यह ऊपर 6502 की तरह हो सकता है, जहाँ सभी 3 रजिस्टरों को बस संचालित करने की आवश्यकता होती है , और अपना नंबर रखने के लिए कोई अतिरिक्त रजिस्टर नहीं है। हालाँकि, जब यह कहता है कि आप पता नहीं ले सकते, ऐसा इसलिए है क्योंकि रजिस्टरों में पते नहीं हैं। वे प्रोसेसर के हाथ हैं। चूंकि कंपाइलर को आपको कोई पता नहीं देना है, और चूँकि उसका कभी भी कोई पता नहीं चल सकता है, इसलिए कई ऑप्टिमाइज़ेशन अब कंपाइलर के लिए खुले हैं। यह, कह सकता है, संख्या को हमेशा एक रजिस्टर में रखें। यह नहीं है' टी को यह चिंता करने की ज़रूरत नहीं है कि यह कंप्यूटर मेमोरी में कहाँ संग्रहीत है (इसे फिर से प्राप्त करने की आवश्यकता से परे)। यह इसे दूसरे चर में भी सजा सकता है, इसे दूसरे प्रोसेसर को दे सकता है, इसे एक परिवर्तनशील स्थान दे सकता है, आदि।

tl; dr: अल्पकालिक चर जो बहुत सारे गणित करते हैं। एक बार में बहुत अधिक घोषित न करें।


5

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

कीवर्ड का उपयोग लंबे, लंबे समय से किया गया था। जब केवल कुछ रजिस्टर थे जो आपकी तर्जनी का उपयोग करके उन सभी को गिन सकते थे।

लेकिन, जैसा कि मैंने कहा, पदावनत का मतलब यह नहीं है कि आप इसका उपयोग नहीं कर सकते।


13
कुछ पुराने हार्डवेयर में आधुनिक इंटेल मशीनों की तुलना में अधिक रजिस्टरों थे। रजिस्टर मायने रखता है कि उम्र और सीपीयू वास्तुकला के साथ क्या करना है।
मेरे सही ऑपरेशन

2
@JUSTMYcorrectOPINION दरअसल, X86 में मूल रूप से छह हैं, जो 'रजिस्टर' के लिए समर्पण के लिए सबसे अधिक 1 या 2 पर हैं। वास्तव में, चूंकि बहुत सारे कोड लिखे गए हैं या रजिस्टर-खराब मशीन में पोर्ट किए गए हैं, मुझे संदेह है कि यह 'रजिस्टर' कीवर्ड के लिए एक प्लेसबो बनने में बहुत योगदान देता है - रजिस्टर में संकेत देने का कोई मतलब नहीं है जब कोई भी नहीं हो। यहां हम 4+ साल बाद हैं और शुक्र है कि x86_64 ने इसे 14 पर ले लिया है, और ARM अब एक बड़ी चीज है।
ग्राग्गो

4

तुलना के लिए बस थोड़ा सा डेमो (बिना किसी वास्तविक दुनिया के उद्देश्य): registerप्रत्येक चर से पहले कीवर्ड हटाते समय , कोड का यह टुकड़ा मेरे i7 (जीसीसी) पर 3.41 सेकंड लेता है, उसी कोड के साथ register 0.7 सेकंड में पूरा होता है।

#include <stdio.h>

int main(int argc, char** argv) {

     register int numIterations = 20000;    

     register int i=0;
     unsigned long val=0;

    for (i; i<numIterations+1; i++)
    {
        register int j=0;
        for (j;j<i;j++) 
        {
            val=j+i;
        }
    }
    printf("%d", val);
    return 0;
}

2
Gcc 4.8.4 और -O3 के साथ, मुझे कोई फर्क नहीं पड़ता। -O3 और 40000 पुनरावृत्तियों के बिना, मुझे 1.5 के कुल समय में शायद 50 एमएस कम मिलता है , लेकिन मैंने यह जानने के लिए पर्याप्त बार नहीं चलाया कि क्या यह सांख्यिकीय रूप से भी महत्वपूर्ण था।
zstewart

CLANG 5.0 के साथ कोई अंतर नहीं है, प्लेटफार्म AMD64 है। (मैंने ASM आउटपुट की जाँच की है।)
ern0

4

मैंने निम्न कोड का उपयोग करके QNX 6.5.0 के तहत रजिस्टर कीवर्ड का परीक्षण किया है:

#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <sys/neutrino.h>
#include <sys/syspage.h>

int main(int argc, char *argv[]) {
    uint64_t cps, cycle1, cycle2, ncycles;
    double sec;
    register int a=0, b = 1, c = 3, i;

    cycle1 = ClockCycles();

    for(i = 0; i < 100000000; i++)
        a = ((a + b + c) * c) / 2;

    cycle2 = ClockCycles();
    ncycles = cycle2 - cycle1;
    printf("%lld cycles elapsed\n", ncycles);

    cps = SYSPAGE_ENTRY(qtime) -> cycles_per_sec;
    printf("This system has %lld cycles per second\n", cps);
    sec = (double)ncycles/cps;
    printf("The cycles in seconds is %f\n", sec);

    return EXIT_SUCCESS;
}

मुझे निम्नलिखित परिणाम मिले:

-> 807679611 चक्र समाप्त हुए

-> इस प्रणाली में प्रति सेकंड 3300830000 चक्र हैं

-> सेकंड में चक्र ~ 0.244600 है

और अब बिना रजिस्टर इंट:

int a=0, b = 1, c = 3, i;

मुझे मिला:

-> 1421694077 चक्र समाप्त हो गए

-> इस प्रणाली में प्रति सेकंड 3300830000 चक्र हैं

-> सेकंड में चक्र ~ 0.430700 है


2

रजिस्टर संकलक को सूचित करेगा कि कोडर का मानना ​​है कि चर का उपयोग करने के लिए उपलब्ध कुछ रजिस्टरों में से एक में इसके भंडारण को सही ठहराने के लिए इस चर को लिखा / पढ़ा जाएगा। रजिस्टरों से पढ़ना / लिखना आमतौर पर तेज़ होता है और इसके लिए छोटे ऑप-कोड सेट की आवश्यकता होती है।

आजकल, यह बहुत उपयोगी नहीं है, क्योंकि अधिकांश कंपाइलर्स ऑप्टिमाइज़र यह निर्धारित करने में आपसे बेहतर हैं कि क्या उस चर के लिए और कितने समय के लिए एक रजिस्टर का उपयोग किया जाना चाहिए।


2

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

आजकल, ऑप्टिमाइज़र प्रोग्रामर को निर्धारित करने के लिए प्रोग्रामर की तुलना में बहुत अधिक कुशल होते हैं, जिन्हें रजिस्टरों में रखने की अधिक संभावना होती है, और ऑप्टिमाइज़र हमेशा प्रोग्रामर के संकेत को ध्यान में नहीं रखता है।

इतने सारे लोग गलत तरीके से रजिस्टर कीवर्ड का उपयोग नहीं करने की सलाह देते हैं।

आइए देखें क्यों!

रजिस्टर कीवर्ड का एक संबद्ध साइड इफेक्ट है: आप एक रजिस्टर प्रकार चर का संदर्भ (पता प्राप्त नहीं कर सकते हैं)।

दूसरों को रजिस्टर का उपयोग न करने की सलाह देने वाले लोग इसे एक अतिरिक्त तर्क के रूप में गलत तरीके से लेते हैं।

हालांकि, यह जानने का सरल तथ्य कि आप एक रजिस्टर चर का पता नहीं लगा सकते हैं, संकलक (और इसके ऑप्टिमाइज़र) को यह जानने की अनुमति देता है कि इस चर का मूल्य अप्रत्यक्ष रूप से एक सूचक के माध्यम से संशोधित नहीं किया जा सकता है।

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

अपने खुद के परीक्षण करें और आपको अपने सबसे आंतरिक छोरों में महत्वपूर्ण प्रदर्शन में सुधार मिलेगा।

c_register_side_effect_performance_boost


1

समर्थित C कंपाइलर्स पर यह कोड को ऑप्टिमाइज़ करने की कोशिश करता है ताकि वेरिएबल की वैल्यू को वास्तविक प्रोसेसर रजिस्टर में रखा जाए।


1

registerवैश्विक रजिस्टर-आवंटन अनुकूलन (/ Oe संकलक ध्वज) सक्षम होने पर Microsoft का दृश्य C ++ कंपाइलर कीवर्ड को अनदेखा करता है।

MSDN पर रजिस्टर कीवर्ड देखें ।


1

रजिस्टर कीवर्ड कंपाइलर को सीपीयू रजिस्टरों में विशेष चर को स्टोर करने के लिए कहता है ताकि यह तेजी से सुलभ हो सके। एक प्रोग्रामर के दृष्टिकोण से रजिस्टर कीवर्ड का उपयोग उन चर के लिए किया जाता है जो किसी प्रोग्राम में भारी उपयोग किए जाते हैं, ताकि कंपाइलर कोड को गति दे सके। हालांकि यह कंपाइलर पर निर्भर करता है कि वह वेरिएबल को सीपीयू रजिस्टर या मुख्य मेमोरी में रखे या नहीं।


0

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

एक और बात यह है कि यदि आप एक चर को रजिस्टर के रूप में घोषित करते हैं तो आप इसका पता नहीं लगा सकते क्योंकि यह मेमोरी में संग्रहीत नहीं है। यह सीपीयू रजिस्टर में अपना आवंटन प्राप्त करता है।


0

gc 9.3 asm आउटपुट, ऑप्टिमाइज़ेशन फ़्लैग्स का उपयोग किए बिना (इस उत्तर में सब कुछ ऑप्टिमाइज़ेशन फ़्लैग्स के बिना मानक संकलन का संदर्भ देता है):

#include <stdio.h>
int main(void) {
  int i = 3;
  i++;
  printf("%d", i);
  return 0;
}
.LC0:
        .string "%d"
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-4], 3
        add     DWORD PTR [rbp-4], 1
        mov     eax, DWORD PTR [rbp-4]
        mov     esi, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        mov     eax, 0
        leave 
        ret
#include <stdio.h>
int main(void) {
  register int i = 3;
  i++;
  printf("%d", i);
  return 0;
}
.LC0:
        .string "%d"
main:
        push    rbp
        mov     rbp, rsp
        push    rbx
        sub     rsp, 8
        mov     ebx, 3
        add     ebx, 1
        mov     esi, ebx
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        add     rsp, 8
        pop     rbx
        pop     rbp
        ret

यह बल ebxगणना के लिए उपयोग किया जाता है, जिसका अर्थ है कि इसे स्टैक पर धकेल दिया जाना चाहिए और फ़ंक्शन के अंत में बहाल कर दिया जाना चाहिए क्योंकि यह शांत है। registerकोड और 1 मेमोरी राइट और 1 मेमोरी रीड की अधिक पंक्तियों का उत्पादन करता है (हालांकि वास्तविक रूप से, यह 0 आर / डब्ल्यूएस के लिए अनुकूलित किया जा सकता है यदि गणना में किया गया है esi, जो कि C ++ 's का उपयोग करके होता है const register)। register2 लिखने और 1 पढ़ने के कारण का उपयोग नहीं करते (हालांकि अग्रेषण को लोड करने के लिए स्टोर रीड पर होगा)। इसका कारण यह है कि मान को सीधे स्टैक पर उपस्थित और अपडेट किया जाना है, इसलिए सही मान पते (पॉइंटर) द्वारा पढ़ा जा सकता है। registerइसकी आवश्यकता नहीं है और इसे इंगित नहीं किया जा सकता है। constऔर registerमूल रूप से इसके विपरीत volatileऔर उपयोग कर रहे हैंvolatileफ़ाइल और ब्लॉक स्कोप registerपर कॉन्स्टिपेशन ऑप्टिमाइज़ेशन और ब्लॉक-स्कोप पर ऑप्टिमाइज़ेशन को ओवरराइड करेगा । const registerऔर registerसमान आउटपुट उत्पन्न करेंगे क्योंकि ब्लॉक-सी पर कास्ट सी पर कुछ भी नहीं करता है, इसलिए केवल registerऑप्टिमाइज़ेशन लागू होते हैं।

क्लैंग पर registerनजरअंदाज कर दिया जाता है, लेकिन constअभी भी अनुकूलन होता है।

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