यह स्रोत कोड सी में एक स्ट्रिंग पर स्विच कर रहा है। यह कैसे करता है?


106

मैं कुछ एमुलेटर कोड के माध्यम से पढ़ रहा हूँ और मैंने कुछ सही मायने में अजीब गिना है:

switch (reg){
    case 'eax':
    /* and so on*/
}

यह कैसे हो सकता है? मुझे लगा कि आप केवल switchअभिन्न प्रकार पर ही कर सकते हैं। क्या कुछ स्थूल प्रवंचना चल रही है?


29
यह स्ट्रिंग नहीं है 'eax'और यह निरंतर पूर्णांक मान
P__J__

12
सिंगल कोट्स, डबल नहीं। एक चरित्र निरंतर को बढ़ावा दिया जाता है int, इसलिए यह कानूनी है। हालाँकि, बहु-वर्ण स्थिरांक का मान कार्यान्वयन-परिभाषित है, इसलिए कोड किसी अन्य संकलक पर अपेक्षित रूप से काम नहीं कर सकता है। उदाहरण के लिए, eaxहो सकता है 0x65, 0x656178, 0x65617800, 0x786165, 0x6165, या कुछ और।
डेविस्लर

2
@Davislor: चर "reg" का नाम दिया गया है, और तथ्य यह है कि eax एक x86 रजिस्टर है, मुझे लगता है कि कार्यान्वयन-परिभाषित व्यवहार ठीक होने का इरादा था, क्योंकि यह कोड में उपयोग किए जाने वाले हर जगह समान है। जब तक 'eax' != 'ebx', निश्चित रूप से, तब तक यह केवल आपके उदाहरणों में से एक या दो को विफल करता है। हालांकि कहीं न कहीं कुछ कोड हो सकता है जो प्रभाव ग्रहण करता है *(int*)("eax") == 'eax', और इसलिए आपके अधिकांश उदाहरणों को विफल करता है।
स्टीव जेसोप

2
@SteveJessop आप जो कहते हैं, मैं उससे असहमत नहीं हूं, लेकिन वास्तविक खतरा यह है कि कोई व्यक्ति एक अलग संकलक पर कोड संकलित करने की कोशिश कर सकता है, यहां तक ​​कि एक ही वास्तुकला के लिए, और अलग व्यवहार प्राप्त कर सकता है। उदाहरण के लिए, के 'eax'बराबर 'ebx'या से तुलना कर सकते हैं 'ax', और स्विच स्टेटमेंट के अनुसार काम नहीं करेगा।
डेविस्लर

1
यदि आप ने हमें डेटा प्रकार के reg को देखा / दिखाया है, तो यह सभी रहस्य जल्दी से दूर हो गए होंगे।
ths

जवाबों:


146

(केवल आप "मैक्रो ट्रिकरी" भाग का जवाब दे सकते हैं - जब तक कि आप अधिक कोड पेस्ट नहीं करते हैं। लेकिन मैक्रोज़ के लिए काम करने के लिए यहां बहुत कुछ नहीं है - औपचारिक रूप से आपको कीवर्ड को फिर से परिभाषित करने की अनुमति नहीं है ; ऐसा करने पर व्यवहार अपरिभाषित है।)

कार्यक्रम की पठनीयता हासिल करने के लिए, मजाकिया डेवलपर कार्यान्वयन परिभाषित व्यवहार का शोषण कर रहा है'eax'है एक स्ट्रिंग है, लेकिन एक बहु चरित्र निरंतर । ध्यान से चारों ओर एकल उद्धरण वर्णों को ध्यान से देखें eax। सबसे अधिक संभावना है कि यह आपको intआपके मामले में दे रहा है जो कि पात्रों के संयोजन के लिए अद्वितीय है। (काफी बार प्रत्येक वर्ण एक 32 बिट में 8 बिट्स पर कब्जा कर लेता है int)। और हर कोई जानता है कि आप switchएक पर कर सकते हैं int!

अंत में, एक मानक संदर्भ:

C99 मानक कहता है:

6.4.4.4p10: "एक पूर्णांक वर्ण का मान जिसमें एक से अधिक वर्ण हों (जैसे, 'अब'), या एक ऐसा पात्र या एस्केप अनुक्रम होता है, जो एकल-बाइट निष्पादन वर्ण पर मैप नहीं करता है, कार्यान्वयन-परिभाषित है। "


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

7
@ जस्टिन जबकि यह हो सकता है, यह काफी विकृत होगा। यदि यह वह नहीं करता है जो उत्तर बताता है कि सबसे अधिक संभावना है, तो अगली संभावना यह है कि यह सिर्फ पहले चरित्र का उपयोग करता है और बाकी की उपेक्षा करता है।
बमर

5
@ZanLynx मैं सकारात्मक नहीं हूं, लेकिन मेरा मानना ​​है कि फीचर लंबे समय से यूनिकोड और अन्य एमबीसीएस मानकों को दर्शाता है। "मैजिक नंबर" जो मेमोरी डंप में टेक्स्ट की तरह दिखते हैं और आरआईएफएफ-स्टाइल फाइल-फॉर्मेट-चंक आईडी पहले एप्लिकेशन थे जिनके बारे में मुझे पता है।
रसेल बोरोगोव

16
@ jpmc26 यह अपरिभाषित व्यवहार नहीं है, यह कार्यान्वयन-परिभाषित है। इसलिए जब तक संकलक प्रलेखन राक्षसों का उल्लेख नहीं करता है, तब तक आपकी नाक सुरक्षित है।
बरमार B ’

7
@ZanLynx: मुझे डर है कि मूल इरादे में यूनिकोड, UTF-8 और किसी भी मल्टीबैट कैरेक्टर एन्कोडिंग से लगभग 20 साल पहले की भविष्यवाणी है। बहु-चरित्र स्थिरांक 2, 3 या 4 बाइट्स (बाइट और अंतर आकार के आधार पर) के समूहों का प्रतिनिधित्व करने वाले पूर्णांक को व्यक्त करने का एक आसान तरीका था। कार्यान्वयन और आर्किटेक्चर के बीच असंगतताओं ने समिति को इसे कार्यान्वयन के रूप में घोषित करने का नेतृत्व किया , जिसका अर्थ है कि और 'ab'से मूल्य की गणना करने का कोई पोर्टेबल तरीका नहीं है । 'a''b'
चकरली

45

सी स्टैंडर्ड के अनुसार (6.8.4.2 स्विच स्टेटमेंट)

3 प्रत्येक केस लेबल की अभिव्यक्ति पूर्णांक स्थिर अभिव्यक्ति होगी ...

और (6.6 लगातार भाव)

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

अब क्या है 'eax'?

सी स्टैंडर्ड (6.4.4.4 वर्ण स्थिरांक)

2 एक पूर्णांक वर्ण स्थिर एकल-उद्धरणों में संलग्न एक या अधिक मल्टीबाइट वर्णों का एक क्रम है , जैसा कि 'x' में है ...

तो 'eax'उसी खंड के पैराग्राफ 10 के अनुसार एक पूर्णांक वर्ण स्थिर है

  1. ... एक पूर्णांक वर्ण मान का मान जिसमें एक से अधिक वर्ण होते हैं (जैसे, 'अब'), या एक ऐसा पात्र या एस्केप अनुक्रम होता है जो एकल-बाइट निष्पादन वर्ण पर मैप नहीं करता है, कार्यान्वयन-परिभाषित है।

तो पहले उल्लेखित उद्धरण के अनुसार यह पूर्णांक स्थिर अभिव्यक्ति का एक ऑपरेंड हो सकता है जिसे केस लेबल के रूप में उपयोग किया जा सकता है।

इस बात पर ध्यान दें कि एक चरित्र स्थिरांक (एकल उद्धरणों में संलग्न) का प्रकार है intऔर एक स्ट्रिंग शाब्दिक (दोहरे उद्धरण चिह्नों में संलग्न वर्णों का एक क्रम) के समान नहीं है जिसमें एक वर्ण सरणी का एक प्रकार है।


12

जैसा कि अन्य ने कहा है, यह एक intस्थिर है और इसका वास्तविक मूल्य कार्यान्वयन-परिभाषित है।

मुझे लगता है कि बाकी कोड कुछ इस तरह दिखता है

if (SOMETHING)
    reg='eax';
...
switch (reg){
    case 'eax':
    /* and so on*/
}

आप यह सुनिश्चित कर सकते हैं कि पहले भाग में 'ईएक्स' का दूसरे भाग में 'ईएक्सएक्स' के समान मूल्य है, इसलिए यह सब ठीक है? ... गलत।

एक टिप्पणी में @Davislor 'eax' के कुछ संभावित मूल्यों को सूचीबद्ध करता है:

... 0x65, 0x656178, 0x65617800, 0x786165, 0x6165, या कुछ और

पहले संभावित मूल्य पर ध्यान दें? यह सिर्फ 'e'अन्य दो पात्रों की अनदेखी है। समस्या कार्यक्रम शायद का उपयोग करता है 'eax', 'ebx', और इतने पर। यदि इन सभी स्थिरांक का मूल्य समान है जैसा कि 'e'आप समाप्त करते हैं

switch (reg){
    case 'e':
       ...
    case 'e':
       ...
    ...
}

यह बहुत अच्छा नहीं लगता है, यह करता है?

"कार्यान्वयन-परिभाषित" के बारे में अच्छा हिस्सा यह है कि प्रोग्रामर अपने संकलक के दस्तावेज की जांच कर सकता है और देख सकता है कि क्या यह इन स्थिरांक के साथ कुछ समझदार है। अगर ऐसा होता है, घर मुक्त।

खराब हिस्सा यह है कि कुछ अन्य गरीब साथी कोड ले सकते हैं और कुछ अन्य संकलक का उपयोग करके इसे संकलित करने का प्रयास कर सकते हैं। त्वरित संकलन त्रुटि। कार्यक्रम पोर्टेबल नहीं है।

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


1
कुछ के अलावा किसी भी तरह से कुछ assert('eax' != 'ebx'); //if this fails you can't compile the code because...भी है मूल लेखक पूरी तरह से निर्माण की जगह के बिना अन्य संकलक विफलताओं को रोकने के लिए कर सकता है
Dan Is Fiddling By Firelight

6
समान मान वाले दो केस लेबल एक बाधा उल्लंघन हैं (6.8.4.2p3: "... एक ही स्विच स्टेटमेंट में केस के दो स्थिर अभिव्यक्ति में रूपांतरण के बाद समान मूल्य नहीं होगा"), जब तक कि सभी कोड इन स्थिरांक के मूल्यों को अपारदर्शी मानते हैं, यह या तो काम करने या संकलन करने में विफल होने की गारंटी है।
zwol

इससे भी बुरी बात यह है कि दूसरे कंपाइलर पर कंपाइल करने वाले खराब साथी को कोई कंपाइल-टाइम एरर नहीं दिखेगा (इनट्स पर स्विच करना ठीक है); इसके बजाय, रन-टाइम त्रुटियाँ
सामने आएंगी

1

कोड टुकड़ा नामक एक ऐतिहासिक विषमता का उपयोग करता है बहु चरित्र चरित्र निरंतर , यह भी कहा जाता बहु वर्ण

'eax' एक पूर्णांक स्थिरांक है जिसका मूल्य क्रियान्वयन परिभाषित है।

यहाँ बहु-वर्णों पर एक दिलचस्प पृष्ठ है और उनका उपयोग कैसे किया जा सकता है लेकिन नहीं करना चाहिए:

http://www.zipcon.net/~swhite/docs/computers/languages/c_multi-char_const.html


रियरव्यू मिरर में आगे पीछे देखते हुए, यहां बताया गया है कि अच्छे पुराने दिनों से डेनिस रिची द्वारा मूल सी मैनुअल ( https://www.bell-labs.com/usr/dmr/www/cman.pdf ) निर्दिष्ट चरित्र स्थिरांक ।

२.३.२ वर्ण स्थिरांक

एक वर्ण स्थिर एकल उद्धरण '' ''' में संलग्न 1 या 2 वर्ण हैं । एक पात्र के भीतर एक एकल उद्धरण एक बैक-स्लेश '' \'' से पहले होना चाहिए । कुछ गैर-ग्राफ़िक वर्ण और \स्वयं '' '', निम्न तालिका के अनुसार बच सकते हैं:

    BS \b
    NL \n
    CR \r
    HT \t
    ddd \ddd
    \ \\

भागने '' \ddd'' में 1, 2 या 3 अष्टक के बाद का बैकस्लैश शामिल है, जो वांछित वर्ण का मान निर्दिष्ट करने के लिए लिया जाता है। इस निर्माण का एक विशेष मामला '' \0'' है (अंक के बाद नहीं) जो एक अशक्त चरित्र को दर्शाता है।

चरित्र स्थिरांक बिल्कुल पूर्णांक की तरह व्यवहार करते हैं (विशेष रूप से, चरित्र प्रकार की वस्तुओं की तरह नहीं)। पीडीपी -11 की संबोधित संरचना के अनुरूप, लंबाई 1 के एक चरित्र स्थिरांक में निम्न-क्रम बाइट में दिए गए वर्ण और उच्च-क्रम बाइट में 0 के लिए कोड होता है; लंबाई 2 के एक चरित्र निरंतर में कम बाइट में पहले चरित्र के लिए कोड है और उच्च क्रम बाइट में दूसरे चरित्र के लिए है। एक से अधिक वर्ण वाले चरित्र स्थिरांक स्वाभाविक रूप से मशीन पर निर्भर होते हैं और इनसे बचा जाना चाहिए।

अंतिम वाक्यांश आप सभी को इस जिज्ञासु निर्माण के बारे में याद रखने की आवश्यकता है: एक से अधिक वर्ण वाले चरित्र स्थिरांक स्वाभाविक रूप से मशीन-निर्भर होते हैं और इनसे बचा जाना चाहिए।

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