क्या यह संकलक के लिए एक स्थानीय अस्थिर चर को अनुकूलित करने की अनुमति है?


79

कंपाइलर को इसे ऑप्टिमाइज़ करने की अनुमति है (C ++ 17 मानक के अनुसार):

int fn() {
    volatile int x = 0;
    return x;
}

इसके लिए?

int fn() {
    return 0;
}

यदि हाँ, तो क्यों? यदि नहीं, तो क्यों नहीं?


इस विषय के बारे में कुछ सोच रहे हैं: वर्तमान संकलक fn()एक स्थानीय चर के रूप में संकलित करते हैं, फिर इसे वापस करते हैं। उदाहरण के लिए, x86-64 पर, gcc इसे बनाता है:

mov    DWORD PTR [rsp-0x4],0x0 // this is x
mov    eax,DWORD PTR [rsp-0x4] // eax is the return register
ret    

अब, जहां तक ​​मुझे पता है कि मानक यह नहीं कहता है कि स्टैक पर एक स्थानीय अस्थिर चर डाला जाना चाहिए। तो, यह संस्करण भी उतना ही अच्छा होगा:

mov    edx,0x0 // this is x
mov    eax,edx // eax is the return
ret    

यहाँ, edxभंडार x। लेकिन अब, यहाँ क्यों रुकना? जैसा कि edxऔर eaxदोनों शून्य हैं, हम कह सकते हैं:

xor    eax,eax // eax is the return, and x as well
ret    

और हम fn()अनुकूलित संस्करण में बदल गए। क्या यह परिवर्तन वैध है? यदि नहीं, तो कौन सा कदम अमान्य है?


1
टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।


@philipxy: यह "क्या उत्पादन कर सकता है" के बारे में नहीं है। यह इस बारे में है कि क्या परिवर्तन की अनुमति है। क्योंकि, अगर इसकी अनुमति नहीं है, तो इसे परिवर्तित संस्करण का उत्पादन नहीं करना चाहिए
जीजा

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

1
@philipxy: मैं अपने प्रश्न को स्पष्ट करूँगा कि यह मानक के बारे में है। यह आमतौर पर इस तरह के सवालों से प्रभावित होता है। मुझे दिलचस्पी है कि मानक क्या कहते हैं।
जीजा

जवाबों:


63

नहीं volatile वस्तुओं व्यवहार्य माना जाता है, बिल्कुल I / O के रूप में, स्थानीय और ग्लोबल्स के बीच कोई विशेष अंतर नहीं है।

एक अनुरूप कार्यान्वयन पर सबसे कम आवश्यकताएं हैं:

  • तक पहुंच volatileअमूर्त मशीन के नियमों के अनुसार वस्तुओं का कड़ाई से मूल्यांकन किया जाता है।

[...]

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

N3690, [intro.execution], int8

यह वास्तव में कैसे अवलोकनीय है, यह मानक के दायरे से बाहर है, और सीधे कार्यान्वयन-विशिष्ट क्षेत्र में गिरता है, बिल्कुल I / O और वैश्विक volatileवस्तुओं तक पहुंच के रूप में । volatileइसका मतलब है कि "आपको लगता है कि आप यहां चल रही हर चीज को जानते हैं, लेकिन यह ऐसा नहीं है। मुझ पर भरोसा करें और इस सामान को बहुत स्मार्ट होने के बिना करें, क्योंकि मैं आपके कार्यक्रम में अपने बाइट के साथ अपना गुप्त सामान कर रहा हूं"। यह वास्तव में [dcl.type.cv] ]7 पर समझाया गया है:

[नोट: volatileऑब्जेक्ट को शामिल करने वाले आक्रामक अनुकूलन से बचने के लिए कार्यान्वयन के लिए एक संकेत है क्योंकि ऑब्जेक्ट के मूल्य को एक कार्यान्वयन द्वारा अवांछनीय द्वारा बदला जा सकता है। इसके अलावा, कुछ कार्यान्वयनों के लिए, अस्थिरता संकेत कर सकती है कि ऑब्जेक्ट तक पहुंचने के लिए विशेष हार्डवेयर निर्देश आवश्यक हैं। विस्तृत शब्दार्थ के लिए 1.9 देखें। सामान्य तौर पर, वाष्पशील का शब्दार्थ सी ++ में समान होता है क्योंकि वे सी - एंड नोट में होते हैं]


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

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

12

इस लूप को यथा-नियम से दूर रखा जा सकता है क्योंकि इसका कोई देखने योग्य व्यवहार नहीं है:

for (unsigned i = 0; i < n; ++i) { bool looped = true; }

यह एक नहीं कर सकता:

for (unsigned i = 0; i < n; ++i) { volatile bool looped = true; }

दूसरा लूप हर पुनरावृत्ति पर कुछ करता है, जिसका अर्थ है कि लूप O (n) समय लेता है। मुझे पता नहीं है कि निरंतर क्या है, लेकिन मैं इसे माप सकता हूं और फिर मेरे पास एक (अधिक या कम) ज्ञात राशि के लिए व्यस्त लूपिंग का एक तरीका है।

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

यदि संकलक loopedएक रजिस्टर में रखना चुनता है , तो मुझे लगता है कि मेरे पास इसके खिलाफ कोई अच्छा तर्क नहीं है। लेकिन यह अभी भी हर लूप पुनरावृत्ति के लिए उस रजिस्टर के मूल्य को 1 पर सेट करना होगा।


तो, क्या आप अंतिम xor ax, ax(जहां axमाना जाता है volatile x) संस्करण को सवाल में वैध, या अमान्य कह रहे हैं ? IOW, सवाल का आपका जवाब क्या है?
हाइड

@ मि: प्रश्न, जैसा कि मैंने इसे पढ़ा था, "क्या चर को समाप्त किया जा सकता है" और मेरा उत्तर "नहीं" है। विशिष्ट x86 कार्यान्वयन के लिए जो इस सवाल को उठाता है कि क्या वाष्पशील को एक रजिस्टर में रखा जा सकता है, मुझे पूरी तरह से यकीन नहीं है। भले ही यह कम हो जाए xor ax, ax, हालांकि, अगर वह बेकार दिखता है, तो भी ओपकोड को समाप्त नहीं किया जा सकता है और न ही इसे विलय किया जा सकता है। मेरे लूप उदाहरण में, संकलित कोड को देखने xor ax, axयोग्य व्यवहार नियम को पूरा करने के लिए n बार निष्पादित करना होगा । उम्मीद है कि संपादित आपके प्रश्न का उत्तर दे।
रिची

हाँ, इस सवाल को संपादित करने से थोड़ा विस्तार हुआ, लेकिन जब से आपने संपादन के बाद उत्तर दिया है, मुझे लगा कि इस उत्तर को नए भाग को कवर करना चाहिए ...
'23

2
@ प्रेस: ​​वास्तव में, मैं बेंचमार्क में उस तरह से वाष्पशील का उपयोग करता हूं ताकि कंपाइलर एक लूप को दूर करने से बच सके जो अन्यथा कुछ भी नहीं करता है। इसलिए मुझे वास्तव में उम्मीद है कि मैं इस बारे में सही हूं: =)
20

स्टैंडर्ड का कहना है कि volatileवस्तुओं पर होने वाले ऑपरेशन स्वयं के - एक प्रकार के दुष्प्रभाव हैं। एक कार्यान्वयन उनके शब्दार्थ को इस तरह से परिभाषित कर सकता है जिससे उन्हें किसी भी वास्तविक सीपीयू निर्देश को उत्पन्न करने की आवश्यकता नहीं होगी, लेकिन एक लूप जो एक वाष्पशील-योग्य वस्तु तक पहुंचता है, उसके साइड इफेक्ट होते हैं और इस तरह वह एलिज़न के लिए योग्य नहीं है।
सुपरकैट

10

मैं पूरी तरह से समझने के बावजूद बहुसंख्यक राय से volatileविमुख होना चाहता हूं, जिसका मतलब है कि मैं / ओ।

यदि आपके पास यह कोड है:

{
    volatile int x;
    x = 0;
}

मेरा मानना है कि संकलक कर सकते हैं के तहत इसे दूर का अनुकूलन के रूप में करता है, तो नियम , यह सोचते हैं कि:

  1. volatileचर अन्यथा दिखाई बाह्य नहीं किया जाता है के माध्यम से जैसे संकेत दिए गए हैं (जो स्पष्ट रूप से एक समस्या यहाँ नहीं है के बाद से वहाँ दिए गए दायरे में ऐसी कोई बात नहीं है)

  2. संकलक आपको बाहरी रूप से एक्सेस करने के लिए एक तंत्र प्रदान नहीं करता है volatile

कसौटी बस यह है कि आप मानदंड # 2 के कारण, वैसे भी अंतर का निरीक्षण नहीं कर सकते हैं।

हालाँकि, आपके कंपाइलर में, मानदंड # 2 संतुष्ट नहीं हो सकता है ! कंपाइलर आपको "बाहर" से चर देखने के बारे में अतिरिक्त गारंटी प्रदान करने का प्रयास कर सकता हैvolatile , जैसे कि स्टैक का विश्लेषण करके। ऐसी स्थितियों में, व्यवहार वास्तव में अवलोकन योग्य है, इसलिए इसे दूर नहीं किया जा सकता है।

अब सवाल यह है कि क्या उपरोक्त कोड उपरोक्त से अलग है?

{
    volatile int x = 0;
}

मेरा मानना ​​है कि मैंने अनुकूलन के संबंध में विज़ुअल सी ++ में इसके लिए अलग व्यवहार देखा है, लेकिन मैं इस आधार पर पूरी तरह से निश्चित नहीं हूं। यह हो सकता है कि आरंभीकरण को "पहुंच" के रूप में नहीं गिना जाए? मुझे यकीन नहीं है। यदि आप रुचि रखते हैं तो यह एक अलग प्रश्न के लायक हो सकता है, लेकिन अन्यथा मुझे विश्वास है कि जैसा मैंने ऊपर बताया है इसका उत्तर है।


6

सैद्धांतिक रूप से, एक बाधा हैंडलर सकता है

  • जाँच करें कि रिटर्न पता fn()फ़ंक्शन के भीतर आता है या नहीं । यह इंस्ट्रूमेंटेशन या संलग्न डिबग जानकारी के माध्यम से प्रतीक तालिका या स्रोत लाइन नंबरों तक पहुंच सकता है।
  • तब के मूल्य को बदलें x, जो स्टैक पॉइंटर से एक पूर्वानुमानित ऑफसेट पर संग्रहीत किया जाएगा।

... इस प्रकार fn()वापसी नॉनज़रो वैल्यू बना रही है ।


1
या आप इसमें ब्रेकपॉइंट सेट करके डीबगर के साथ अधिक आसानी से कर सकते हैं fn()volatileकोड-जीन का उपयोग करना gcc -O0उस चर के लिए जैसा होता है: हर सी स्टेटमेंट के बीच स्पिल / रीलोड। ( -O0डिबगर निरंतरता को तोड़ने के बिना अभी भी एक बयान के भीतर कई एक्सेस को जोड़ सकते हैं, लेकिन volatileऐसा करने की अनुमति नहीं है।)
पीटर कॉर्ड्स

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

यहां तक ​​कि, इसका क्या मतलब है "अवलोकनीय"? क्या इसे स्टैक पर रखा जाना चाहिए? अगर कोई रजिस्टर रखता है तो क्या होगा x? क्या होता है अगर x86-64 पर, xor rax, raxशून्य को धारण करता है (मेरा मतलब है, रिटर्न-वैल्यू-रजिस्टर होल्ड x), जो निश्चित रूप से डिबगर द्वारा आसानी से देखा जा सकता है / संशोधित किया जा सकता है (यानी, डिबग प्रतीक जानकारी रखता है xजो इसमें संग्रहीत है rax)। क्या यह मानक का उल्लंघन करता है?
जीजा

2
−1 किसी भी कॉल को fn()इनलाइन किया जा सकता है। MSVC 2017 और डिफ़ॉल्ट रिलीज़ मोड के साथ, यह है। तब कोई " fn()फ़ंक्शन के भीतर " नहीं है। भले ही, चर स्वचालित भंडारण के बाद से कोई "अनुमानित ऑफसेट" नहीं है।
चीयर्स एंड हीथ। - अल्फ

1
0 @berendi: हाँ आप इसके बारे में सही हैं, और मैं इसके बारे में गलत था। क्षमा करें, उस सम्मान में मेरे लिए बुरी सुबह (दो बार गलत)। फिर भी यह IMO बेकार है यह तर्क देने के लिए कि कंपाइलर अन्य सॉफ़्टवेयर के माध्यम से एक्सेस का समर्थन कैसे कर सकता है, क्योंकि यह ऐसा कर सकता है volatile, और क्योंकि volatileयह उस समर्थन को प्रदान करने के लिए मजबूर नहीं करता है। और इसलिए मैं डाउनवोट हटाता हूं (मैं गलत था), लेकिन मैं अपवोट नहीं करता, क्योंकि मुझे लगता है कि तर्क की यह रेखा स्पष्ट नहीं कर रही है।
चीयर्स एंड हीथ। - अल्फ

6

मैं सिर्फ as-if नियम और अस्थिर कीवर्ड के लिए एक विस्तृत संदर्भ जोड़ने जा रहा हूं । (इन पृष्ठों के निचले भाग में, मूल चश्मे को वापस ट्रेस करने के लिए "यह भी देखें" और "संदर्भ" का पालन करें, लेकिन मुझे पढ़ने / समझने के लिए cppreference.com बहुत आसान लगता है।)

विशेष रूप से, मैं चाहता हूं कि आप इस खंड को पढ़ें

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

इसलिए विशेष रूप से वाष्पशील कीवर्ड ग्लवल्स पर संकलक अनुकूलन को अक्षम करने के बारे में है । यहां केवल एक चीज जो वाष्पशील कीवर्ड को प्रभावित कर सकती है return x, संभवतः , कंपाइलर बाकी फ़ंक्शन के साथ जो चाहे कर सकता है।

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

साइड नोट: इन मामलों में, हमेशा मान लें कि संकलक आपके इच्छित / विपरीत के विपरीत काम करेगा। आपको या तो अनुकूलन को अक्षम करना चाहिए (कम से कम इस मॉड्यूल के लिए), या जो आप चाहते हैं उसके लिए एक अधिक परिभाषित व्यवहार खोजने की कोशिश करें। (यह भी क्यों यूनिट परीक्षण इतना महत्वपूर्ण है) यदि आप मानते हैं कि यह एक दोष है, तो आपको इसे सी ++ के डेवलपर्स के साथ लाना चाहिए।


यह सब पढ़ना अभी भी कठिन है, इसलिए जो मुझे लगता है कि यह प्रासंगिक है उसे शामिल करने की कोशिश कर रहा है ताकि आप इसे स्वयं पढ़ सकें।

glvalue एक glvalue अभिव्यक्ति या तो lvalue या xvalue है।

गुण:

एक प्रचलन को कथित रूप से एक प्रचलन में लवल्यू-टू-रिवल्यू, एरे-टू-पॉइंटर या फ़ंक्शन-टू-पॉइंटर निहित रूपांतरण के साथ परिवर्तित किया जा सकता है। एक ग्लव्यू बहुरूपक हो सकता है: जिस गतिशील प्रकार की पहचान करता है वह जरूरी नहीं कि अभिव्यक्ति का स्थिर प्रकार है। एक चमक में अपूर्ण प्रकार हो सकता है, जहां अभिव्यक्ति की अनुमति है।


xvalue निम्नलिखित अभिव्यक्तियाँ xvalue अभिव्यक्तियाँ हैं:

एक फ़ंक्शन कॉल या एक अतिभारित ऑपरेटर अभिव्यक्ति, जिसका वापसी प्रकार वस्तु के लिए संदर्भ है, जैसे कि std :: move (x); एक [एन], बिल्ट-इन सबस्क्रिप्ट अभिव्यक्ति, जहां एक ऑपरेंड एक सरणी व्याप्त है; am, ऑब्जेक्ट एक्सप्रेशन का सदस्य, जहाँ एक a rvalue है और m एक गैर-स्थैतिक डेटा गैर-संदर्भ प्रकार का सदस्य है; a। * एमपी, ऑब्जेक्ट एक्सप्रेशन के सदस्य के लिए पॉइंटर, जहां एक रव्यू है और एमपी डेटा सदस्य के लिए एक पॉइंटर है; ए ? बी: सी, कुछ बी और सी के लिए टर्नेरी सशर्त अभिव्यक्ति (विस्तार के लिए परिभाषा देखें); ऑब्जेक्ट प्रकार, जैसे कि static_cast (x) के संदर्भ के संदर्भ में एक कास्ट एक्सप्रेशन; कोई भी अभिव्यक्ति जो अस्थायी वस्तुकरण के बाद, एक अस्थायी वस्तु को डिजाइन करती है। (C ++ 17 के बाद से) गुण:

नीचे के रूप में समान (नीचे)। नीचे के समान चमक (नीचे)। विशेष रूप से, सभी अंतरालों की तरह, xvalues ​​संदर्भ संदर्भों को बांधते हैं, और सभी गल्र्स की तरह, xvalues ​​बहुरूपी हो सकते हैं, और गैर-श्रेणी के xvalues ​​cv- योग्य हो सकते हैं।


lvalue निम्नलिखित अभिव्यक्तियाँ lvalue अभिव्यक्तियाँ हैं:

एक चर, एक फ़ंक्शन, या एक डेटा सदस्य का नाम, प्रकार की परवाह किए बिना, जैसे std :: cin या std :: endl। यहां तक ​​कि अगर चर के प्रकार का संदर्भ संदर्भ है, तो इसके नाम से संबंधित अभिव्यक्ति एक लवल्यू अभिव्यक्ति है; एक फ़ंक्शन कॉल या एक अतिभारित ऑपरेटर अभिव्यक्ति, जिसका वापसी प्रकार lvalue संदर्भ है, जैसे std :: getline (std :: cin, str), std :: cout << 1, str1 = str2, या ++ it; a = b, a + = b, a% = b, और अन्य सभी अंतर्निहित असाइनमेंट और कंपाउंड असाइनमेंट एक्सप्रेशन; ++ a और --a, बिल्ट-इन प्री-इन्क्रीमेंट और प्री-डिक्रीमेंट एक्सप्रेशन; * पी, अंतर्निहित अप्रत्यक्ष अभिव्यक्ति; एक [एन] और पी [एन], बिल्ट-इन सबस्क्रिप्ट अभिव्यक्तियों को छोड़कर, जहां एक एरे रिवेल्यू है (सी 11 11 के बाद से); एम, ऑब्जेक्ट एक्सप्रेशन का सदस्य, जहां मी सदस्य एन्यूमरेटर या गैर-स्थैतिक सदस्य फ़ंक्शन है, को छोड़कर या जहां एक rvalue और m गैर-संदर्भ प्रकार का एक गैर-स्थैतिक डेटा सदस्य है; p-> मी, पॉइंटर एक्सप्रेशन का बिल्ट-इन मेंबर, सिवाय इसके कि एम कहाँ मेंबर एन्यूमरेटर या नॉन-स्टैटिक मेंबर फंक्शन है; a। * mp, ऑब्जेक्ट एक्सप्रेशन के सदस्य के लिए पॉइंटर, जहां एक lvalue है और mp डेटा सदस्य के लिए एक पॉइंटर है; p -> * MP, बिल्ट-इन पॉइंटर से मेम्बर ऑफ़ पॉइंटर एक्सप्रेशन, जहाँ mp डेटा पॉइंटर का पॉइंटर है; ए, बी, बिल्ट-इन कॉमा अभिव्यक्ति, जहां बी एक लैवल्यू है; ए ? बी: सी, कुछ बी और सी (जैसे, जब दोनों एक ही प्रकार के अंतराल होते हैं, लेकिन विस्तार के लिए परिभाषा देखें) के लिए टर्नरी सशर्त अभिव्यक्ति; एक स्ट्रिंग शाब्दिक, जैसे "हैलो, दुनिया!"; संदर्भ प्रकार को स्थिर करने के लिए एक कास्ट एक्सप्रेशन, जैसे कि static_cast (x); एक फ़ंक्शन कॉल या एक अतिभारित ऑपरेटर अभिव्यक्ति, जिसका वापसी प्रकार कार्य करने के लिए संदर्भ है; फ़ंक्शन प्रकार, जैसे कि static_cast (x) के संदर्भ के संदर्भ में एक कास्ट एक्सप्रेशन। (C ++ 11 के बाद से) गुण:

नीचे के समान चमक (नीचे)। एक लेवल्यू का पता लिया जा सकता है: & ++ i 1 और & std :: एंडल वैध अभिव्यक्ति हैं। एक अंतर्निहित लैवल्यू का उपयोग बिल्ट-इन असाइनमेंट और कंपाउंड असाइनमेंट ऑपरेटर्स के बाएं हाथ के ऑपरेंड के रूप में किया जा सकता है। एक लैवल्यू का उपयोग एक लैवल्यू संदर्भ को इनिशियलाइज़ करने के लिए किया जा सकता है; यह अभिव्यक्ति द्वारा पहचाने गए ऑब्जेक्ट के साथ एक नया नाम जोड़ता है।


जैसा कि अगर नियम है

C ++ कंपाइलर को प्रोग्राम में किसी भी परिवर्तन को करने की अनुमति है, जब तक कि यह सही रहता है:

1) प्रत्येक अनुक्रम बिंदु पर, सभी अस्थिर वस्तुओं के मूल्य स्थिर होते हैं (पिछले मूल्यांकन पूर्ण होते हैं, नए मूल्यांकन शुरू नहीं हुए हैं) (C ++ 11 तक) 1) अस्थिर वस्तुओं तक पहुँच (पढ़ता और लिखता) शब्दार्थ के अनुसार सख्ती से होता है जिन भावों में वे घटित होते हैं। विशेष रूप से, वे एक ही धागे पर अन्य अस्थिर पहुंच के संबंध में पुन: व्यवस्थित नहीं होते हैं। (C ++ 11 के बाद से) 2) प्रोग्राम समाप्ति पर, फ़ाइलों को लिखे गए डेटा बिल्कुल वैसा ही है जैसे प्रोग्राम को लिखित रूप में निष्पादित किया गया था। 3) इनपुट के लिए प्रोग्राम का इंतजार करने से पहले इंटरेक्टिंग डिवाइस को भेजे गए टेक्स्ट को दिखाया जाएगा। 4) यदि ISO C प्रगम्मा #pragma STDC FENV_ACCESS समर्थित है और चालू है


यदि आप चश्मा पढ़ना चाहते हैं, तो मेरा मानना ​​है कि ये वही हैं जिन्हें आपको पढ़ना चाहिए

संदर्भ

सी 11 मानक (आईएसओ / आईईसी 9899: 2011): 6.7.3 प्रकार के क्वालिफायर (पी: 121-123)

C99 मानक (ISO / IEC 9899: 1999): 6.7.3 प्रकार क्वालिफायर (पी: 108-110)

C89 / C90 मानक (ISO / IEC 9899: 1990): 3.5.3 प्रकार के क्वालिफायर


यह मानक के अनुसार सही नहीं हो सकता है, लेकिन निष्पादन के दौरान किसी और चीज को छूने के लिए स्टैक पर निर्भर किसी को भी कोडिंग बंद कर देना चाहिए। मेरा तर्क है कि यह एक मानक दोष है।
मेनडेलल

1
@ मेनडेलल: इस तरह से एक दावा व्यापक है। _AddressOfReturnAddressउदाहरण के लिए, स्टैक का विश्लेषण करना शामिल है। लोग मान्य कारणों के लिए स्टैक का विश्लेषण करते हैं, और यह आवश्यक नहीं है क्योंकि फ़ंक्शन स्वयं शुद्धता के लिए इस पर निर्भर करता है।
user541686

1
: glvalue यहाँ हैreturn x;
गेज़ा

@geza क्षमा करें, यह सब पढ़ना मुश्किल है। क्या यह एक चमक है क्योंकि x एक चर है? इसके अलावा, "के लिए अनुकूलित नहीं किया जा सकता", इसका मतलब यह है कि संकलक बिल्कुल भी अनुकूलन नहीं कर सकता है, या यह कि अभिव्यक्ति को बदलकर अनुकूलन नहीं कर सकता है? (यह पढ़ता है कि कंपाइलर को अभी भी यहाँ अनुकूलन करने की अनुमति है क्योंकि उनके बनाए रखने के लिए कोई एक्सेस ऑर्डर नहीं है, और अभिव्यक्ति अभी भी हल हो रही है, बस अधिक अनुकूलित तरीके से) मैं देख सकता हूं कि दोनों तरीकों से उच्च समझ के बिना बहस की जा रही है ऐनक।
तेजा

यहाँ अपने खुद के जवाब से एक उद्धरण है :) "निम्नलिखित अभिव्यक्तियाँ lvalue अभिव्यक्तियाँ हैं: एक चर का नाम ..."
भूजा

-1

मुझे लगता है कि मैंने कभी भी अस्थिर का उपयोग करते हुए एक स्थानीय चर नहीं देखा है जो एक अस्थिर के लिए एक संकेतक नहीं था। जैसे की:

int fn() {
    volatile int *x = (volatile int *)0xDEADBEEF;
    *x = 23;   // request data, 23 = temperature 
    return *x; // return temperature
}

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

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


3
लेकिन यह एक स्थानीय अस्थिर चर नहीं है, यह एक स्थानीय गैर-वाष्पशील सूचक है जो एक प्रसिद्ध पते पर एक अस्थिर अंतर है।
बेकार

जिससे सही व्यवहार के बारे में तर्क करना आसान हो जाता है। जैसा कि कहा जाता है कि स्थानीय वैरिएबल और पॉइंटर्स के लिए अस्थिर वैरिएबल तक पहुँचने के नियम समान हैं।
गोसविन वॉन ब्रेडरलो

मैं आपके उत्तर के पहले वाक्य को संबोधित कर रहा हूं, जो यह बताता है कि xआपके कोड में "स्थानीय अस्थिर चर" है। यह नहीं है।
बेकार

मैं पागल हो गया जब int fn (कॉन्स्टाइल वाष्पशील int तर्क) संकलन नहीं किया।
जोशुआ

4
संपादन आपके उत्तर को गलत नहीं बनाता है, लेकिन यह केवल प्रश्न का उत्तर नहीं देता है। यह पाठ्यपुस्तक का उपयोग-मामला है volatile, और इसका स्थानीय होने से कोई लेना-देना नहीं है। यह सिर्फ static volatile int *const x = ...वैश्विक दायरे में हो सकता है और आप जो कुछ भी कहते हैं वह अभी भी बिल्कुल वैसा ही होगा। यह अतिरिक्त पृष्ठभूमि ज्ञान की तरह है जो प्रश्न को समझने के लिए आवश्यक है, जो मुझे लगता है कि शायद हर किसी के पास नहीं है, लेकिन यह एक वास्तविक उत्तर नहीं है।
पीटर कॉर्ड्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.