क्या सी ++ संकलक बेकार कोष्ठक को हटा / अनुकूलित करता है?


19

कोड होगा

int a = ((1 + 2) + 3); // Easy to read

की तुलना में धीमी गति से चलाएं

int a = 1 + 2 + 3; // (Barely) Not quite so easy to read

या "बेकार" कोष्ठक को हटाने / अनुकूलित करने के लिए आधुनिक कंपाइलर काफी चतुर हैं।

यह एक बहुत छोटे अनुकूलन चिंता की तरह लग सकता है, लेकिन C ++ / जावा / ... पर C ++ चुनना सभी अनुकूलन (IMHO) के बारे में है।


9
मुझे लगता है कि C # और Java भी इसका अनुकूलन करेंगे। मेरा मानना ​​है कि जब वे पार्स करते हैं और एएसटी बनाते हैं, तो वे बस उस तरह स्पष्ट बेकार सामान निकाल देंगे।
फरीद नूरी नेष्ट

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

7
... RAII और स्मार्ट पॉइंटर्स की तुलना में, इसलिए यह उन भाषाओं में गेम प्रोग्रामिंग करने के अपेक्षाकृत अप्राप्य पथ (सी ++) के अच्छी तरह से पीटे जाने के बाद का सवाल है। मैं यह भी नोट करूंगा कि कोष्ठक के बारे में चिंता करना पागलपन है - मैं देख रहा हूं कि आप कहां से आ रहे हैं, लेकिन यह एक हास्यास्पद सूक्ष्म अनुकूलन है। आपके कार्यक्रम में डेटा संरचनाओं और एल्गोरिदम की पसंद निश्चित रूप से प्रदर्शन पर हावी होगी, ऐसी तुच्छता नहीं।
डोभाल

6
उम ... आप किस तरह के अनुकूलन की उम्मीद कर रहे हैं, बिल्कुल? यदि आप स्थैतिक विश्लेषण के बारे में बात कर रहे हैं, तो अधिकांश भाषाओं में, जिनके बारे में मुझे पता है, यह सांख्यिकीय रूप से ज्ञात परिणाम (LLVM- आधारित कार्यान्वयन यहां तक ​​कि इसे लागू करने वाले AFAIK) द्वारा प्रतिस्थापित किया जाएगा। यदि आप निष्पादन आदेश के बारे में बात कर रहे हैं, तो यह कोई फर्क नहीं पड़ता, क्योंकि यह एक ही ऑपरेशन और साइड इफेक्ट्स के बिना है। इसके अलावा, दो ऑपरेंड की जरूरत है। और यदि आप प्रदर्शन के संबंध में C ++, Java और C # की तुलना करने के लिए इसका उपयोग कर रहे हैं, तो ऐसा लगता है कि आपको इस बात का स्पष्ट पता नहीं है कि अनुकूलन क्या हैं और वे कैसे काम करते हैं, इसलिए आपको इसके बजाय सीखने पर ध्यान केंद्रित करना चाहिए।
थियोडोरोस चटजिआनियाकिस

5
मुझे आश्चर्य है कि क्यों ) आप कोष्ठक अभिव्यक्ति को अधिक पठनीय मानते हैं (मेरे लिए यह सिर्फ बदसूरत, भ्रामक लगता है (वे इस विशेष आदेश पर जोर क्यों देते हैं? क्या यह यहाँ आत्मसात नहीं होना चाहिए?) और क्लंकी) बी) आप इसके बिना क्यों चाहेंगे? कोष्ठक यह बेहतर प्रदर्शन कर सकता है (स्पष्ट रूप से पार्सिंग पार्न्स एक मशीन के लिए आसान है , ऑपरेटर ऑपरेटर के बारे में कारण के रूप में। जैसा कि मार्क वैन लेउवेन कहते हैं, हालांकि, यह पूरी तरह से रनटाइम पर कोई प्रभाव नहीं है)।
लेफ्टनैबाउटआउट

जवाबों:


87

संकलक वास्तव में कोष्ठक को कभी सम्मिलित या हटाता नहीं है; यह आपकी अभिव्यक्ति के अनुरूप केवल एक पार्स ट्री (जिसमें कोई कोष्ठक मौजूद नहीं है) बनाता है, और ऐसा करने पर आपको लिखे गए कोष्ठकों का सम्मान करना चाहिए। यदि आप अपनी अभिव्यक्ति को पूरी तरह से संक्षिप्त करते हैं तो यह भी तुरंत मानवीय पाठक को स्पष्ट हो जाएगा कि वह पेड़ क्या है; यदि आप बिना किसी अतिरेक के लघु कोष्ठक में डालने के चरम पर जाते हैं, int a = (((0)));तो आपको परिणामी पार्स ट्री को बदलने के बिना, और इसके परिणामस्वरूप उत्पन्न कोड को बदलकर, पार्सर में कुछ चक्रों को बर्बाद करते हुए पाठक के न्यूरॉन्स पर कुछ बेकार तनाव पैदा होगा। ) जरा सा।

यदि आप कोई कोष्ठक नहीं लिखते हैं, तो पार्सर को अभी भी एक पार्स ट्री बनाने का काम करना चाहिए, और ऑपरेटर पूर्वता और सहानुभूति के नियम यह बताते हैं कि वास्तव में किस पार्स ट्री का निर्माण करना चाहिए। आप उन नियमों को संकलक के रूप में विचार कर सकते हैं जो (निहित) कोष्ठक को आपके कोड में सम्मिलित करना चाहिए , हालांकि पार्सर वास्तव में इस मामले में कोष्ठक के साथ कभी भी व्यवहार नहीं करता है: यह सिर्फ उसी पार्स पेड़ के उत्पादन के लिए बनाया गया है जैसे कि माता-पिता कुछ निश्चित स्थानों पर मौजूद थे। यदि आप कोष्ठक को उन स्थानों पर रखते हैं, जैसे कि int a = (1+2)+3;( +बायीं ओर की समतुल्यता) तो परसर थोड़े अलग मार्ग से उसी परिणाम पर पहुंचेगा। यदि आप अलग-अलग कोष्ठकों में डालते हैंint a = 1+(2+3);तब आप एक अलग तोते के पेड़ के लिए मजबूर कर रहे हैं, जो संभवतः अलग-अलग कोड उत्पन्न करेगा (हालांकि शायद नहीं, क्योंकि कंपाइलर पार्स पेड़ के निर्माण के बाद परिवर्तन लागू कर सकता है, जब तक कि परिणामी कोड को निष्पादित करने का प्रभाव कभी अलग नहीं होगा। यह)। माना जाता है कि रीसेलिंग कोड में अंतर होता है, सामान्य तौर पर ऐसा कुछ नहीं कहा जा सकता है जो अधिक कुशल हो; सबसे महत्वपूर्ण बिंदु यह है कि ज्यादातर समय तोते के पेड़ गणितीय रूप से समकक्ष अभिव्यक्ति नहीं देते हैं, इसलिए उनकी निष्पादन गति की तुलना बिंदु के बगल में होती है: किसी को बस अभिव्यक्ति लिखना चाहिए ताकि उचित परिणाम मिल सके।

तो यह है कि: शुद्धता के लिए आवश्यकतानुसार कोष्ठक का उपयोग करें, और पठनीयता के लिए वांछित; यदि निरर्थक वे निष्पादन की गति (और संकलन समय पर एक नगण्य प्रभाव) पर कोई प्रभाव नहीं है।

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


एस / oldes / सबसे पुराने /। अच्छा उत्तर, +1।
डेविड कॉनरैड

23
कुल नाइटिक चेतावनी: "सवाल बहुत अच्छी तरह से नहीं रखा गया है" - मैं असहमत हूं, "अच्छी तरह से डाल" का मतलब है "स्पष्ट रूप से सुझाव देना कि कौन सा ज्ञान अंतर को भरा जाना चाहता है"। संक्षेप में यह सवाल है कि "एक्स के लिए अनुकूलन, ए या बी चुनें, और क्यों? नीचे क्या होता है?", जो कम से कम मेरे लिए बहुत स्पष्ट रूप से सुझाव देता है कि ज्ञान अंतर क्या है। प्रश्न में दोष, जिसे आप ठीक से इंगित करते हैं और बहुत अच्छी तरह से संबोधित करते हैं, यह है कि यह एक दोषपूर्ण मानसिक मॉडल पर बनाया गया है।
जोनास कोल्कर

के लिए a = b + c * d;, a = b + (c * d);[हानिरहित] अनावश्यक कोष्ठक होगा। यदि वे कोड को अधिक पठनीय बनाने में आपकी मदद करते हैं, तो ठीक है। a = (b + c) * d;गैर-निरर्थक कोष्ठक होंगे - वे वास्तव में परिणामी पार्स पेड़ को बदलते हैं और एक अलग परिणाम देते हैं। करने के लिए पूरी तरह से कानूनी (वास्तव में, आवश्यक), लेकिन वे निहित डिफ़ॉल्ट समूहन के समान नहीं हैं।
फिल पेरी

1
@ ऑरेंजडॉग सच है, इसकी शर्म की बात है कि बेन की टिप्पणी ने कुछ लोगों को उकसाया जो वीएम का दावा करना पसंद करते हैं।
gbjbaanb

1
@ जोनासकोल्कर: मेरा शुरुआती वाक्य वास्तव में शीर्षक में तैयार किए गए प्रश्न को संदर्भित करता है: कोई वास्तव में इस सवाल का जवाब नहीं दे सकता है कि कंपाइलर कोष्ठक को सम्मिलित करता है या हटाता है, क्योंकि यह गलत धारणा है कि संकलक कैसे काम करते हैं। लेकिन मैं मानता हूं कि यह स्पष्ट है कि किस ज्ञान अंतर को संबोधित करने की आवश्यकता है।
मार्क वैन लीउवेन

46

कोष्ठक आपके लाभ के लिए पूरी तरह से हैं - संकलक नहीं। कंपाइलर आपके कथन का प्रतिनिधित्व करने के लिए सही मशीन कोड बनाएगा।

FYI करें, कंपाइलर पूरी तरह से इसे अनुकूलित करने के लिए काफी चतुर है अगर यह हो सकता है। आपके उदाहरणों में, यह int a = 6;संकलन के समय में बदल जाएगा ।


9
बिल्कुल - आप के रूप में कई कोष्ठक के रूप में छड़ी और संकलक पता लगाने की कड़ी मेहनत करते हैं कि आप क्या चाहते हैं :)
gbjbaanb

23
@ सर्ज सच्चा प्रोग्रामिंग प्रदर्शन के बारे में आपके कोड की पठनीयता के बारे में अधिक है। जब आप एक दुर्घटना को डीबग करने की आवश्यकता होती है तो आप अगले साल खुद से नफरत करेंगे और आपके पास केवल "अनुकूलित" कोड होना चाहिए।
शाफ़्ट फ्रिक

1
@ratchetfreak, आप सही हैं फिर भी मुझे पता है कि मुझे अपना कोड कैसे लिखना है। int a = 6; // = (1 + 2) + 3
सर्ज

20
@Serge मुझे पता है कि समय टिप्पणी में तोड़ मरोड़ के एक साल के बाद पकड़ नहीं होगा, और कोड सिंक्रनाइज़ेशन से बाहर जाना होगा और फिर आप के साथ अंतint a = 8;// = 2*3 + 5
रैशे सनकी

21
या www.thedailywtf.com से:int five = 7; //HR made us change this to six...
मूविंग डक

23

आपके द्वारा पूछे गए प्रश्न का उत्तर नहीं है, लेकिन आपके द्वारा पूछे गए प्रश्न का उत्तर हां है। कोष्ठक जोड़ना कोड को धीमा नहीं करता है।

आपने ऑप्टिमाइज़ेशन के बारे में एक प्रश्न पूछा था, लेकिन कोष्ठक का अनुकूलन से कोई लेना-देना नहीं है। संकलक उत्पन्न कोड के आकार या गति (कभी-कभी दोनों) को बेहतर बनाने के इरादे से विभिन्न अनुकूलन तकनीकों को लागू करता है। उदाहरण के लिए, यह अभिव्यक्ति A ^ 2 (A चुकता) ले सकता है और इसे तेजी से यदि कोई X A (खुद से गुणा करता है) से बदल सकता है। यहाँ उत्तर नहीं है, संकलक अपने अनुकूलन चरण में कुछ अलग नहीं करता है, यह इस बात पर निर्भर करता है कि क्या कोष्ठक मौजूद नहीं हैं।

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

मुझे ध्यान से कहना चाहिए। यदि आप कोष्ठकों को एक ऐसी अभिव्यक्ति में जोड़ते हैं जो कड़ाई से अनावश्यक होती है (किसी अभिव्यक्ति के मूल्यांकन के अर्थ या आदेश पर कोई प्रभाव नहीं पड़ता है) तो कंपाइलर चुपचाप उन्हें त्याग देगा और समान कोड उत्पन्न करेगा।

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

short int a = 30001, b = 30002, c = 30003;
int d = -a + b + c;    // ok
int d = (-a + b) + c;  // ok, same code
int d = (-a + b + c);  // ok, same code
int d = ((((-a + b)) + c));  // ok, same code
int d = -a + (b + c);  // undefined behaviour, different code

इसलिए यदि आप चाहते हैं तो कोष्ठक जोड़ें, लेकिन सुनिश्चित करें कि वे वास्तव में अनावश्यक हैं!

मैं कभी नही करता हूँ। वास्तविक लाभ नहीं होने पर त्रुटि का खतरा है।


फुटनोट: अहस्ताक्षरित व्यवहार तब होता है जब एक हस्ताक्षरित पूर्णांक अभिव्यक्ति उस मान के मूल्यांकन का मूल्यांकन करती है जो उस सीमा के बाहर होता है जिसे वह व्यक्त कर सकता है, इस स्थिति में -32767 से +32767। यह एक जटिल विषय है, इस उत्तर के दायरे से बाहर।


अंतिम पंक्ति में अनिर्धारित व्यवहार इसलिए है क्योंकि हस्ताक्षरित शॉर्ट में केवल हस्ताक्षर के बाद 15 बिट्स हैं, इसलिए अधिकतम आकार 32767 है, है ना? उस तुच्छ उदाहरण में, संकलक को अतिप्रवाह के बारे में चेतावनी देनी चाहिए, है ना? एक काउंटर उदाहरण के लिए, किसी भी तरह से। यदि वे एक समारोह के पैरामीटर थे, तो आपको चेतावनी नहीं मिलेगी। इसके अलावा, अगर aवास्तव में अहस्ताक्षरित किया -a + bजा सकता है, तो aनकारात्मक और bसकारात्मक होने पर अपनी गणना को आसानी से समाप्त कर सकते हैं ।
पैट्रिक एम

@ पैट्रिकम: संपादन देखें। अपरिभाषित व्यवहार का मतलब है कि संकलक वह कर सकता है जो उसे पसंद है, जिसमें चेतावनी जारी करना शामिल है, या नहीं। Unsigned अंकगणित यूबी का उत्पादन नहीं करता है, लेकिन दो की अगली उच्च शक्ति modulo कम हो जाता है।
david.pfx

(b+c)अंतिम पंक्ति में अभिव्यक्ति इसके तर्कों को बढ़ावा देगी int, इसलिए जब तक कंपाइलर int16 बिट्स को परिभाषित नहीं करता है (या तो क्योंकि यह प्राचीन है या एक छोटे माइक्रोकंट्रोलर को लक्षित करता है) अंतिम पंक्ति पूरी तरह से वैध होगी।
सुपरकैट

@ सुपरकैट: मुझे ऐसा नहीं लगता। परिणाम का सामान्य प्रकार और प्रकार संक्षिप्त अंतर होना चाहिए। यदि ऐसा कुछ नहीं है जो कभी पूछा गया है, तो शायद आप एक प्रश्न पोस्ट करना चाहते हैं?
david.pfx

@ david.pfx: C अंकगणितीय पदोन्नति के नियम बहुत स्पष्ट हैं: सब कुछ छोटे से intप्रचारित हो जाता है intजब तक कि वह उस प्रकार के सभी मूल्यों का प्रतिनिधित्व करने में असमर्थ हो जाता है जिस स्थिति में उसका प्रचार किया जाता है unsigned int। कंपाइलर पदोन्नति को छोड़ सकते हैं यदि सभी परिभाषित व्यवहार समान होंगे जैसे कि प्रोन्नति को शामिल किया गया था । एक मशीन पर जहां 16-बिट प्रकार एक रैपिंग एब्सट्रेक्ट बीजीय रिंग के रूप में व्यवहार करते हैं, (a + b) + c और a (b + c) समतुल्य होंगे। यदि intएक 16-बिट प्रकार था जो अतिप्रवाह पर फंस गया था, लेकिन फिर ऐसे मामले होंगे जहां अभिव्यक्ति में से एक ...
सुपरकैट

7

संचालक पूर्ववर्ती के आदेश में हेरफेर करने के लिए आपके लिए केवल ब्रैकेट हैं। एक बार संकलित होने के बाद, कोष्ठक अब मौजूद नहीं है क्योंकि रन-टाइम को उनकी आवश्यकता नहीं है। संकलन प्रक्रिया सभी कोष्ठक, रिक्त स्थान और अन्य कृत्रिम शर्करा को हटा देती है जिसे आपको और मुझे आवश्यकता है और सभी संचालकों को कंप्यूटर में निष्पादित करने के लिए कुछ [अभी तक] सरल में बदल देती है।

तो, जहाँ आप और मैं देख सकते हैं ...

  • "int a = ((1 + 2) + 3);"

... एक कंपाइलर कुछ इस तरह से निकल सकता है:

  • चार [1] :: "एक"
  • Int32 :: DeclareStackVariable ()
  • Int32 :: 0x00000001
  • Int32 :: 0x00000002
  • Int32 :: जोड़ें ()
  • Int32 :: 0x00000003
  • Int32 :: जोड़ें ()
  • Int32 :: AssignToVariable ()
  • शून्य :: DiscardResult ()

कार्यक्रम को शुरुआत में शुरू करके और प्रत्येक निर्देश को बारी-बारी से निष्पादित किया जाता है।
ऑपरेटर पूर्वता अब "पहले आओ, पहले पाओ" है।
सब कुछ दृढ़ता से लिखा गया है, क्योंकि संकलक सब काम किया है कि बाहर, जबकि यह मूल वाक्य रचना के अलावा फाड़ दिया गया था।

ठीक है, यह उस सामान की तरह नहीं है जिसे आप और मैं निपटाते हैं, लेकिन फिर हम इसे नहीं चला रहे हैं!


4
वहाँ एक भी C ++ संकलक नहीं है जो इस तरह से दूर से भी कुछ भी उत्पादन करेगा। आम तौर पर वे वास्तविक सीपीयू कोड का उत्पादन करते हैं, और असेंबली यह नहीं दिखता है।
MSalters

3
यहाँ आशय था कि लिखित और संकलित आउटपुट के रूप में कोड के बीच संरचना के अंतर को प्रदर्शित किया जाए। यहां तक ​​कि ज्यादातर लोग वास्तविक मशीन कोड या असेंबली को पढ़ने में सक्षम नहीं होंगे
DHall

अगर आप LLVM ISA को like कुछ ऐसा ’(यह SSA स्टैक आधारित नहीं है) के रूप में मानते हैं तो @MSalters Nitpicking clang like कुछ ऐसा ही’ का उत्सर्जन करेगा। यह देखते हुए कि LLVM और JVM ISA के लिए JVM बैकएंड लिखना संभव है (AFAIK) स्टैक आधारित क्लैंग-> llvm-> JVM बहुत समान लगेगा।
मैकीज पीचोटका

मुझे नहीं लगता कि एलएलवीएम आईएसए में रनटाइम स्ट्रिंग शाब्दिक (सिर्फ पहले दो निर्देश) का उपयोग करके स्टैक चर को परिभाषित करने की क्षमता है। यह गंभीरता से रन-टाइम और कंपाइल-टाइम को मिला रहा है। भेद मायने रखता है क्योंकि यह सवाल ठीक उसी उलझन के बारे में है।
MSalters 13’14

6

निर्भर करता है कि यह अस्थायी बिंदु है या नहीं:

  • फ्लोटिंग पॉइंट में अंकगणितीय जोड़ सहयोगी नहीं है, इसलिए ऑप्टिमाइज़र ऑपरेशन को फिर से नहीं कर सकता है (जब तक कि आप फास्टमैथ कंपाउंड स्विच नहीं जोड़ते हैं)।

  • पूर्णांक संचालन में वे पुनः व्यवस्थित हो सकते हैं।

आपके उदाहरण में दोनों ठीक उसी समय चलेंगे क्योंकि वे ठीक उसी कोड का संकलन करेंगे (इसके अलावा इसका मूल्यांकन बाएँ से दाएँ किया जाता है)।

हालाँकि java और C # भी इसे ऑप्टिमाइज़ कर पाएंगे, वे इसे रनटाइम पर ही कर पाएंगे।


फ्लोटिंग पॉइंट ऑपरेशंस को सहयोगी बनाने के लिए +1 नहीं है।
डोभाल

प्रश्न के उदाहरण में कोष्ठक डिफ़ॉल्ट (बाएं) की समरूपता में परिवर्तन नहीं करता है, इसलिए यह बिंदु मूट है।
मार्क वैन लीउवेन

1
अंतिम वाक्य के बारे में, मुझे ऐसा नहीं लगता। Java a और c # दोनों में कंपाइलर अनुकूलित बायोटेक / IL का उत्पादन करेगा। रनटाइम प्रभावित नहीं होता है।
स्टेफानो अल्टिएरी

आईएल इस प्रकार के भावों पर काम नहीं करता है, निर्देश एक स्टैक से कुछ निश्चित मान लेते हैं, और स्टैक की निश्चित संख्या (आमतौर पर 0 या 1) वापस करते हैं। इस प्रकार की बात करना C # में रनटाइम पर ऑप्टिमाइज़ किया जाना बकवास है।
जॉन हैना

6

विशिष्ट C ++ कंपाइलर मशीन कोड में अनुवाद करता है, न कि C ++ में ही । यह बेकार parens को हटा देता है, हाँ, क्योंकि जब तक यह किया जाता है, तब तक कोई parens नहीं होता है। मशीन कोड उस तरह से काम नहीं करता है।


5

दोनों कोड 6 के रूप में हार्ड कोडित हैं:

movl    $6, -4(%rbp)

अपने लिए यहां देखें


2
यह असेंबली क्या है ।ynh.io thingy
पीटर मोर्टेंसन

यह एक छद्म संकलक है जो सी कोड को x86 असेंबली में ऑनलाइन बदल देता है
मोनोअथ्रेडेड

1

नहीं, लेकिन हां, लेकिन शायद, लेकिन शायद दूसरा तरीका, लेकिन नहीं।

जैसा कि लोगों ने पहले ही इंगित किया है, (एक भाषा को छोड़कर जहां जोड़-घटाव है, जैसे C, C ++, C # या Java) अभिव्यक्ति ((1 + 2) + 3)बिल्कुल इसके बराबर है 1 + 2 + 3। वे स्रोत कोड में कुछ लिखने के विभिन्न तरीके हैं, जिसके परिणामस्वरूप मशीन कोड या बाइट कोड पर शून्य प्रभाव होगा।

किसी भी तरह से परिणाम दो अनुदेशों को जोड़ने और फिर एक तिहाई जोड़ने के लिए एक निर्देश होने जा रहा है, या एक स्टैक से दो मान लें, इसे जोड़ें, इसे वापस धक्का दें, फिर इसे और दूसरा लें और उन्हें जोड़ें, या तीन रजिस्टर जोड़ें अगले स्तर (मशीन कोड या बाइट कोड) में जो सबसे अधिक समझदार है, उसके आधार पर तीन संख्याओं को योग करने के लिए एक एकल ऑपरेशन, या कुछ अन्य तरीके। बाइट कोड के मामले में, इसके बदले में एक समान री-स्ट्रक्चरिंग से गुजरना होगा, जैसे कि इस के IL समतुल्य (जो एक स्टैक पर लोड की एक श्रृंखला होगी, और जोड़े को जोड़ने और फिर परिणाम को वापस लाने के लिए पॉपिंग जोड़े) मशीन कोड स्तर पर उस तर्क की एक सीधी प्रतिलिपि में परिणाम नहीं होगा, लेकिन सवाल में मशीन के लिए कुछ और अधिक समझदार।

लेकिन आपके सवाल में कुछ और भी है।

किसी भी सेंस सी, सी ++, जावा, या सी # कंपाइलर के मामले में, मैं उम्मीद करूंगा कि आपके द्वारा दिए गए दोनों कथनों के परिणाम निम्नानुसार होंगे:

int a = 6;

परिणामी कोड को शाब्दिक गणित पर समय बर्बाद क्यों करना चाहिए? प्रोग्राम की स्थिति में कोई परिवर्तन का परिणाम बंद हो जाएगा 1 + 2 + 3जा रहा है 6, ताकि क्या कोड में जाना चाहिए निष्पादित किया जा रहा। वास्तव में, शायद यह भी नहीं है (आप उस 6 के साथ क्या करते हैं, इसके आधार पर, शायद हम पूरी चीज को फेंक सकते हैं, और यहां तक ​​कि सी # के दर्शन के साथ "भारी रूप से अनुकूलन न करें, क्योंकि घबराना इस तरह से अनुकूलन करेगा" या तो उत्पादन करेगा के बराबर int a = 6या सिर्फ पूरी चीज को अनावश्यक के रूप में फेंक दें)।

हालांकि यह हमें आपके प्रश्न के संभावित विस्तार की ओर ले जाता है। निम्नलिखित को धयान मे रखते हुए:

int a = (b - 2) / 2;
/* or */
int a = (b / 2)--;

तथा

int c;
if(d < 100)
  c = 0;
else
  c = d * 31;
/* or */
int c = d < 100 ? 0 : d * 32 - d
/* or */
int c = d < 100 && d * 32 - d;
/* or */
int c = (d < 100) * (d * 32 - d);

(ध्यान दें, यह अंतिम दो उदाहरण C # मान्य नहीं हैं, जबकि यहाँ सब कुछ है, और वे C, C ++ और Java में मान्य हैं।)

यहाँ फिर से हम आउटपुट के मामले में बिलकुल समकक्ष कोड है। जैसा कि वे लगातार अभिव्यक्ति नहीं कर रहे हैं, वे संकलन समय पर गणना नहीं की जाएगी। यह संभव है कि एक रूप दूसरे की तुलना में तेज़ हो। कौन सा तेज है? यह प्रोसेसर पर निर्भर करेगा और शायद राज्य में कुछ मनमाने अंतर पर (विशेष रूप से अगर एक तेज है, तो यह बहुत तेज होने की संभावना नहीं है)।

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

उनमें से प्रत्येक में, संदेह करने का एक कारण है कि एक दूसरे की तुलना में तेज़ हो सकता है। एकल वेतन वृद्धि में एक विशेष निर्देश हो (b / 2)--सकता है , इसलिए वास्तव में इससे भी तेज हो सकता है (b - 2) / 2d * 32शायद तेजी से उत्पादन किया जा सकता है d << 5ताकि यह d * 32 - dतेजी से बना रहे हैं d * 31। पिछले दो के बीच के अंतर विशेष रूप से दिलचस्प हैं; एक कुछ मामलों में कुछ प्रसंस्करण को छोड़ देता है, लेकिन दूसरा शाखा गलत भविष्यवाणी की संभावना से बचता है।

इसलिए, यह हमें दो प्रश्नों के साथ छोड़ देता है: 1. क्या वास्तव में दूसरे की तुलना में तेज़ है? 2. क्या एक कंपाइलर धीमी गति को तेज में परिवर्तित करेगा?

और उत्तर 1. यह निर्भर करता है। 2. शायद।

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

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

यह एक बहुत छोटे अनुकूलन चिंता की तरह लग सकता है,

नहीं, यहां तक ​​कि मेरे द्वारा दिए गए लोगों की तुलना में अधिक जटिल मतभेदों के साथ, यह बिल्कुल मिनट की चिंता की तरह लगता है जिसका अनुकूलन के साथ कोई लेना-देना नहीं है। यदि कुछ भी हो, तो यह निराशा की बात है क्योंकि आपको संदेह है कि पढ़ने के लिए कठिन पढ़ने ((1 + 2) + 3में आसान से अधिक धीमा हो सकता है 1 + 2 + 3

लेकिन C ++ / जावा / ... पर C ++ चुनना सभी अनुकूलन (IMHO) के बारे में है।

अगर यह वास्तव में C # या जावा पर C ++ का चयन करता है, तो "सभी के बारे में" मैं कहूंगा कि लोगों को स्ट्रॉस्ट्रुप और आईएसओ / आईईसी 14882 की अपनी प्रति जलानी चाहिए और कुछ और एमपी 3 या कुछ के लिए कमरे छोड़ने के लिए अपने सी ++ कंपाइलर के स्थान को खाली करना चाहिए।

इन भाषाओं के एक दूसरे पर अलग-अलग फायदे हैं।

उनमें से एक यह है कि सी ++ अभी भी आम तौर पर स्मृति उपयोग पर अधिक तेज़ और हल्का है। हाँ, ऐसे उदाहरण हैं जहां C # और / या जावा तेज़ हैं और / या बेहतर अनुप्रयोग-जीवनकाल मेमोरी का उपयोग करते हैं, और ये अधिक सामान्य होते जा रहे हैं क्योंकि तकनीक में सुधार हुआ है, लेकिन हम अभी भी C ++ में लिखे गए औसत प्रोग्राम की उम्मीद कर सकते हैं एक छोटा निष्पादन योग्य जो अपने काम को तेजी से करता है और उन दोनों भाषाओं में समकक्ष की तुलना में कम मेमोरी का उपयोग करता है।

यह अनुकूलन नहीं है।

ऑप्टिमाइज़ेशन का उपयोग कभी-कभी "चीजों को तेज़ी से बनाने" के लिए किया जाता है। यह समझने योग्य है, क्योंकि अक्सर जब हम "अनुकूलन" के बारे में बात कर रहे होते हैं तो हम वास्तव में चीजों को तेजी से आगे बढ़ाने के बारे में बात कर रहे हैं, और इसलिए एक दूसरे के लिए एक आशुलिपि बन गया है और मैं स्वीकार करता हूं कि मैं इस तरह से शब्द का दुरुपयोग करता हूं।

"चीजें तेजी से आगे बढ़ें" के लिए सही शब्द अनुकूलन नहीं है । यहाँ सही शब्द सुधार है । यदि आप एक कार्यक्रम में बदलाव करते हैं और एकमात्र सार्थक अंतर यह है कि यह अब तेज है, यह किसी भी तरह से अनुकूलित नहीं है, यह सिर्फ बेहतर है।

अनुकूलन तब होता है जब हम किसी विशेष पहलू और / या विशेष मामले के संबंध में सुधार करते हैं। आम उदाहरण हैं:

  1. यह अब एक उपयोग के मामले के लिए तेज़ है, लेकिन दूसरे के लिए धीमा है।
  2. यह अब तेज़ है, लेकिन अधिक मेमोरी का उपयोग करता है।
  3. यह अब स्मृति पर हल्का है, लेकिन धीमा है।
  4. अब यह तेज है, लेकिन इसे बनाए रखना कठिन है।
  5. अब इसे बनाए रखना आसान है, लेकिन धीमी गति से।

ऐसे मामलों को उचित ठहराया जाएगा यदि, उदाहरण के लिए:

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

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

और भाषा की पसंद का यहाँ प्रभाव पड़ता है, क्योंकि गति, स्मृति का उपयोग, और पठनीयता सभी इससे प्रभावित हो सकते हैं, लेकिन इसलिए अन्य प्रणालियों के साथ संगतता, पुस्तकालयों की उपलब्धता, रनटाइम की उपलब्धता, किसी दिए गए ऑपरेटिंग सिस्टम पर उन रनटाइम की परिपक्वता हो सकती है। (अपने पापों के लिए मैंने किसी तरह लिनक्स और एंड्रॉइड को अपनी पसंदीदा OS के रूप में और C # को अपनी पसंदीदा भाषा के रूप में समाप्त किया, और जबकि मोनो महान है, लेकिन मैं अभी भी इस एक के खिलाफ आता हूं)।

यह कहना कि "C ++ / जावा / ... पर C ++ चुनना सभी के लिए अनुकूलन है" केवल तभी समझ में आता है जब आपको लगता है कि C ++ वास्तव में बेकार है, क्योंकि अनुकूलन "बेहतर होने के बावजूद ..." "बेहतर" नहीं है। अगर आपको लगता है कि C ++ अपने आप में बेहतर है, तो आपको जिस आखिरी चीज की आवश्यकता है, वह है ऐसे मिनटों के संभावित माइक्रो-ऑप्स के बारे में चिंता करना। वास्तव में, आप शायद इसे छोड़ना ही बेहतर समझते हैं; खुश हैकर्स भी एक गुणवत्ता के लिए अनुकूलित करने के लिए कर रहे हैं!

यदि फिर भी, आप "I C C से प्यार करते हैं, और जिन चीज़ों से मुझे प्यार है, उनमें से एक अतिरिक्त चक्र को निचोड़ रहा है", तो यह एक अलग बात है। यह अभी भी एक मामला है कि माइक्रो-ऑप्स केवल इसके लायक हैं अगर वे एक रिफ्लेक्सिव आदत हो सकते हैं (यानी, जिस तरह से आप स्वाभाविक रूप से कोड करते हैं, वह धीमी गति से अधिक बार होगा)। अन्यथा वे समय से पहले अनुकूलन नहीं कर रहे हैं, वे समय से पहले निराशा है कि बस चीजों को बदतर बनाते हैं।


0

कोष्ठक संकलक को बताने के लिए हैं जिसमें क्रम अभिव्यक्तियों का मूल्यांकन किया जाना चाहिए। कभी-कभी वे बेकार होते हैं (पठनीयता में सुधार या खराब होने के अलावा), क्योंकि वे उस आदेश को निर्दिष्ट करते हैं जो वैसे भी उपयोग किया जाएगा। कभी-कभी वे क्रम बदल देते हैं। में

int a = 1 + 2 + 3;

व्यावहारिक रूप से अस्तित्व में हर भाषा में एक नियम होता है कि योग का मूल्यांकन 1 + 2 को जोड़कर किया जाता है, फिर परिणाम को जोड़कर 3. यदि आपने लिखा है

int a = 1 + (2 + 3);

फिर कोष्ठक एक अलग क्रम को बाध्य करेगा: पहले 2 + 3 जोड़ रहा है, फिर परिणाम 1 जोड़ रहा है। कोष्ठक का आपका उदाहरण उसी क्रम का उत्पादन करता है जो वैसे भी निर्मित किया गया होगा। अब इस उदाहरण में, संचालन का क्रम थोड़ा अलग है, लेकिन जिस तरह से पूर्णांक काम करता है, उसका परिणाम समान है। में

int a = 10 - (5 - 4);

कोष्ठक महत्वपूर्ण हैं; उन्हें छोड़ने से परिणाम 9 से 1 में बदल जाएगा।

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


practically every language in existence; एपीएल को छोड़कर: कोशिश (यहां) [tryapl.org] प्रवेश (1-2)+3(2), 1-(2+3)(-4) और 1-2+3(-4 भी)।
tomsmeding

0

हालांकि जो कुछ भी कहा गया है, मैं उससे बहुत सहमत हूं, लेकिन ... यहाँ पर आर्च यह है कि कोष्ठक संचालन के क्रम को बनाए रखने के लिए हैं ... जो कंपाइलर बिल्कुल कर रहा है। हां, यह मशीन कोड का उत्पादन करता है ... लेकिन, यह बात नहीं है और यह नहीं पूछा जा रहा है।

कोष्ठक वास्तव में चले गए हैं: जैसा कि कहा गया है, वे मशीन कोड का हिस्सा नहीं हैं, जो संख्याएं हैं और एक चीज नहीं है। असेंबली कोड मशीन कोड नहीं है, यह अर्ध-मानव पठनीय है और इसमें नाम से निर्देश हैं - न कि ओपकोड। मशीन चलाता है जिसे ओपकोड कहा जाता है - विधानसभा भाषा के संख्यात्मक प्रतिनिधित्व।

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


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

ओपी ने पूछा कि क्या कोष्ठक चले गए थे ... मैंने कहा कि वे थे और आगे समझाया गया कि निष्पादन योग्य कोड केवल संख्या है जो ऑपकोड का प्रतिनिधित्व करता है। जावा को दूसरे उत्तर में लाया गया। मुझे लगता है कि यह सवाल का ठीक जवाब देता है ... लेकिन यह केवल मेरी राय है। जवाब के लिए धन्यवाद।
जिंझाई

3
कोष्ठक "ऑपरेशन के आदेश" को मजबूर नहीं करते हैं। वे पूर्वता बदलते हैं। तो, में a = f() + (g() + h());, संकलक मुक्त है कॉल करने के लिए f, gऔर hइसी क्रम में (या किसी भी क्रम में यह प्रसन्न)।
आलोक

मुझे उस कथन से कुछ असहमति है ... आप बिल्कुल कोष्ठक के साथ संचालन के आदेश का पालन कर सकते हैं।
जिंज़ई

0

संकलक, भाषा की परवाह किए बिना, पोस्टफ़िक्स में सभी infix गणित का अनुवाद करते हैं। दूसरे शब्दों में, जब कंपाइलर कुछ देखता है:

((a+b)+c)

यह इस में अनुवाद करता है:

 a b + c +

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

मैं इस विषय पर अधिक जानकारी के लिए रिवर्स पोलिश नोटेशन पर विकिपीडिया लेख की सिफारिश करता हूं ।


5
यह गलत धारणा है कि संकलक कैसे संचालन का अनुवाद करते हैं। आप उदाहरण के लिए यहाँ एक स्टैक मशीन मान रहे हैं। यदि आपके पास एक वेक्टर प्रोसेसर था तो क्या होगा? क्या होगा यदि आपके पास बड़ी मात्रा में रजिस्टरों वाली मशीन थी?
अहमद मसूद
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.