C- शैली की भाषाओं में तार्किक संचालक क्यों नहीं है "" और "~~" नहीं?


39

बाइनरी ऑपरेटरों के लिए हमारे पास बिटवाइज़ और लॉजिकल ऑपरेटर दोनों हैं:

& bitwise AND
| bitwise OR

&& logical AND
|| logical OR

हालांकि (एक अपर संचालक) अलग तरह से व्यवहार नहीं करता है। बिटवाइस के लिए ~ और है! तार्किक के लिए।

मैं नहीं जानता कि AND और OR के विपरीत एक समान संचालन नहीं है, लेकिन मैं इस कारण से नहीं सोच सकता कि डिजाइनरों ने इस सिद्धांत से विचलित करने के लिए चुना कि सिंगल बिटवाइज़ है और डबल यहाँ तार्किक है, और इसके बजाय एक अलग चरित्र के लिए चला गया। मुझे लगता है कि आप इसे गलत तरीके से पढ़ सकते हैं, एक डबल बिटवाइज़ ऑपरेशन की तरह जो हमेशा ऑपरेंड वैल्यू लौटाएगा। लेकिन यह मेरे लिए एक वास्तविक समस्या नहीं है।

क्या कोई कारण है जो मुझे याद आ रहा है?


7
क्योंकि !! मतलब तार्किक नहीं, मैं 42 को 1 में कैसे बदलूंगा? :)
कैंडिड_ऑरेंज

9
चाहेंगे ~~तो नहीं नहीं तार्किक के लिए और अधिक सुसंगत किया गया है, यदि आप पैटर्न है कि तार्किक ऑपरेटर बिटवाइज़ ऑपरेटर का दोहरीकरण है का पालन करें?
बार्ट वैन इनगेन शेनौ सेप

9
सबसे पहले, अगर यह स्थिरता के लिए था, तो यह ~ और ~~ का दोहरीकरण था और शॉर्ट सर्किट से जुड़ा हुआ है; और तार्किक में शॉर्ट सर्किट नहीं होता है।
क्रिस्टोफ

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

7
कुछ टिप्पणियों को पहले से ही करने के लिए (और जो पालन करने के लिए नहीं करना चाहते हैं के लिए alluded किया है इस लिंक , !!foo? एक नहीं असामान्य नहीं है (आम नहीं) मुहावरा है यह करने के लिए एक शून्य या अशून्य तर्क को सामान्य। 0या 1
कीथ थॉम्पसन

जवाबों:


108

अजीब तरह से, सी-स्टाइल प्रोग्रामिंग भाषा का इतिहास सी के साथ शुरू नहीं होता है।

डेनिस रिची इस लेख में सी के जन्म की चुनौतियों को अच्छी तरह से समझाते हैं ।

इसे पढ़ते समय, यह स्पष्ट हो जाता है कि सी को अपने पूर्ववर्ती बीसीपीएल और विशेष रूप से ऑपरेटरों से इसकी भाषा डिजाइन का एक हिस्सा विरासत में मिला । अनुभाग "नवजात सी" ऊपर उल्लिखित लेख के बताते हैं कि कैसे BCPL के &और |दो नए ऑपरेटरों के साथ समृद्ध कर रहे थे &&और ||। कारण थे:

  • के साथ संयोजन में इसके उपयोग के कारण अलग-अलग प्राथमिकता की आवश्यकता थी ==
  • विभिन्न मूल्यांकन तर्क: शॉर्ट-सर्किट के साथ बाएं से दाएं मूल्यांकन (यानी जब में aहोता falseहै a&&b, bतो मूल्यांकन नहीं किया जाता है)।

दिलचस्प है, यह दोहरीकरण पाठक के लिए कोई अस्पष्टता पैदा नहीं करता है: के a && bरूप में गलत व्याख्या नहीं की जाएगी a(&(&b))। परसेंटिंग दृष्टिकोण से, कोई अस्पष्टता भी नहीं है: &bसमझ में आ सकता है कि अगर bएक लैवल्यू था, लेकिन यह एक संकेतक होगा जबकि बिटवाइज़ &को पूर्णांक ऑपरेटर की आवश्यकता होगी, इसलिए तार्किक और एकमात्र उचित विकल्प होगा।

BCPL पहले से ही ~बिटवाइज़ निगेटिव के लिए इस्तेमाल किया जाता है । तो संगति की दृष्टि से, ~~इसका तार्किक अर्थ देने के लिए इसे दोगुना किया जा सकता था । दुर्भाग्य से यह बहुत अस्पष्ट रहा होगा क्योंकि ~एक अपर ऑपरेटर है: ~~bइसका मतलब यह भी हो सकता है ~(~b))। यही कारण है कि लापता उपेक्षा के लिए एक और प्रतीक चुनना पड़ा।


10
पार्सर दो स्थितियों की अवहेलना करने में असमर्थ है, इसलिए भाषा डिजाइनरों को ऐसा करना चाहिए।
BobDalgleish

16
@ पाठ: वास्तव में, सी और सी जैसी भाषाओं में पहले से ही कई समान समस्याएं हैं। जब पार्सर देखता (t)+1है कि यह जोड़ने का एक प्रकार है (t)और 1क्या यह एक +1प्रकार का कलाकार है t? C ++ डिज़ाइन में समस्या को हल करना था कि कैसे टेम्प्लेट को >>सही तरीके से रखा जाए। और इसी तरह।
एरिक लिपर्ट

6
@ user2357112 मुझे लगता है कि यह बात ठीक है कि टोकन लेने वाले &&को आँख बंद करके एक &&टोकन के रूप में लेना ठीक है और दो &टोकन के रूप में नहीं , क्योंकि a & (&b)व्याख्या लिखना एक उचित बात नहीं है, इसलिए एक मानव का यह मतलब कभी नहीं होगा और आश्चर्य होगा संकलक के रूप में यह इलाज a && b। दोनों जबकि !(!a)और !!a, एक मानव मतलब के लिए संभव बातें हैं तो यह संकलक एक मनमाना tokenization स्तर के नियम के साथ अस्पष्टता को हल करने के लिए एक बुरा विचार है।
बेन

17
!!न केवल लिखना संभव / उचित है, बल्कि विहित "बूलियन में परिवर्तित" मुहावरा है।
आर ..

4
मुझे लगता है कि dan04 , --aबनाम की अस्पष्टता का जिक्र कर रहा है -(-a), जो दोनों वाक्यात्मक रूप से मान्य हैं, लेकिन अलग-अलग शब्दार्थ हैं।
रुसलान

49

मैं इस कारण से नहीं सोच सकता कि डिजाइनरों ने इस सिद्धांत से विचलन करने का विकल्प चुना कि सिंगल बिटवाइज़ है और डबल यहाँ तार्किक है,

यह पहली जगह में सिद्धांत नहीं है; एक बार जब आप महसूस करते हैं कि, यह अधिक समझ में आता है।

के बारे में सोचना बेहतर तरीका &बनाम &&नहीं है द्विआधारी और बूलियन । बेहतर तरीका यह है कि आप उन्हें उत्सुक और आलसी समझें&ऑपरेटर बाएँ और दाएँ पक्ष निष्पादित करता है और उसके बाद परिणाम गणना करता है। &&ऑपरेटर बाईं ओर निष्पादित करता है, और फिर दाईं ओर कार्यान्वित केवल आवश्यक हो तो परिणाम की गणना करने के।

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

तो चलो इसे एक साथ रखा। क्या यह बूलियंस की एक सरणी पर एक आलसी ऑपरेशन करने के लिए कोई मतलब है ? नहीं, क्योंकि पहले जांच करने के लिए कोई "बाईं ओर" नहीं है। पहले जांच करने के लिए 32 "बाईं ओर" हैं। इसलिए हम आलसी कार्यों को एक एकल बूलियन तक सीमित रखते हैं , और यहीं पर आपका अंतर्ज्ञान "बाइनरी" है और एक "बूलियन" से आता है, लेकिन यह डिजाइन का एक परिणाम है, न कि स्वयं डिज़ाइन!

और जब आप इस तरह से सोचते हैं, तो यह स्पष्ट हो जाता है कि क्यों !!और क्या नहीं है ^^। न तो उन ऑपरेटरों के पास संपत्ति है जो आप किसी एक ऑपरेंड का विश्लेषण करना छोड़ सकते हैं; कोई "आलसी" notया नहीं है xor

अन्य भाषाएँ इसे और अधिक स्पष्ट करती हैं; कुछ भाषाएं and"उत्सुक" और "लेकिन and also" आलसी और ", उदाहरण के लिए" का अर्थ करती हैं। और अन्य भाषाओं में भी इसे और अधिक स्पष्ट है कि बनाने &और &&"बाइनरी" और "बूलियन" नहीं हैं; उदाहरण के लिए सी # में, दोनों संस्करण बुलियन को ऑपरेंड के रूप में ले सकते हैं।


2
धन्यवाद। यह मेरे लिए असली आंख खोलने वाला है। बहुत बुरा मैं दो जवाब स्वीकार नहीं कर सकता।
मार्टिन Maat

10
मुझे नहीं लगता कि इस के बारे में सोच का एक अच्छा तरीका है &और &&। जबकि उत्सुकता बीच के अंतरों में से एक है &और &&, &एक &&विशेष रूप से उन भाषाओं से पूरी तरह से अलग व्यवहार करती है , खासकर उन भाषाओं में जहां &&एक समर्पित बूलियन प्रकार के अलावा अन्य प्रकारों का समर्थन करता है।
user2357112

14
उदाहरण के लिए, C और C ++ में, 1 & 2से पूरी तरह से अलग परिणाम है 1 && 2
user2357112

7
@ZizyArcher: जैसा कि मैंने ऊपर टिप्पणी में उल्लेख किया है, boolसी में एक प्रकार को छोड़ देने के निर्णय से नॉक-ऑन प्रभाव पड़ता है। हमें दोनों की आवश्यकता है !और ~क्योंकि एक का अर्थ है "एक इंट का इलाज एक एकल बूलियन के रूप में" और एक का अर्थ है "एक इंट को बूलियंस के पैक किए गए सरणी के रूप में व्यवहार करें"। यदि आपके पास अलग-अलग बूल और इंट प्रकार हैं, तो आपके पास बस एक ऑपरेटर हो सकता है, जो मेरी राय में बेहतर डिजाइन होगा, लेकिन हम उस पर लगभग 50 साल देर कर रहे हैं। C # इस डिज़ाइन को परिचितता के लिए सुरक्षित रखता है।
एरिक Lippert

3
@Steve: यदि जवाब बेतुका लगता है तो मैंने कहीं न कहीं एक खराब तरीके से व्यक्त तर्क दिया है, और हमें अधिकार से एक तर्क पर भरोसा नहीं करना चाहिए। क्या आप इसके बारे में अधिक बेतुका कह सकते हैं?
एरिक Lippert

21

टी एल; डॉ

C को दूसरी भाषा से विरासत में मिला !और ~ऑपरेटर। दोनों &&और ||साल बाद एक अलग व्यक्ति द्वारा जोड़ा गया था।

लंबा जवाब

ऐतिहासिक रूप से, C का विकास प्रारंभिक भाषाओं B से हुआ, जो BCPL पर आधारित था, जो CPL पर आधारित था, जो Algol पर आधारित था।

Al ++, C ++, Java और C # के परदादा , एक तरह से सही और गलत को परिभाषित करते हैं, जो प्रोग्रामर्स के लिए सहज महसूस करते हैं: "सत्य मान, जो एक बाइनरी संख्या के रूप में माना जाता है (1 के विपरीत सच और 0 से गलत), आंतरिक अभिन्न मूल्य के रूप में ही ”। हालांकि, इसका एक नुकसान यह है कि तार्किक और बिटवाइज़ एक ही ऑपरेशन नहीं हो सकते हैं: किसी भी आधुनिक कंप्यूटर पर, ~01 के बजाय -1 ~1बराबर है और 0. के बजाय -2 के बराबर है (यहां तक ​​कि कुछ साठ वर्षीय मेनफ्रेम जहां ~0प्रतिनिधित्व करता है - 0 या INT_MIN, ~0 != 1कभी बनाया हर सीपीयू, और सी भाषा मानक पर जबकि इसके बेटी भाषाओं के सबसे भी सहायता साइन-और-परिमाण करने के लिए या one's-पूरक बिल्कुल परेशान नहीं है, कई वर्षों के लिए यह आवश्यक हो गया है।)

अल्गोल ने अलग-अलग विधाओं के साथ काम किया और ऑपरेटरों की बूलियन और इंटीग्रल मोड में अलग-अलग व्याख्या की। यही है, एक बिटवाइज़ ऑपरेशन पूर्णांक प्रकारों पर एक था, और बूलियन प्रकारों पर एक तार्किक ऑपरेशन एक था।

बीसीपीएल के पास एक अलग बूलियन प्रकार था, लेकिन बिटवाइज़ और लॉजिकल दोनों के लिए एक एकल notऑपरेटर । जिस तरह से सी के इस शुरुआती अग्रदूत ने वह काम किया था:

सच का रूल थोड़ा पैटर्न है जो पूरी तरह से लोगों से बना है; असत्य का दोष शून्य है।

ध्यान दें कि true = ~ false

(आप देखेंगे कि अवधि rvalue मतलब कुछ सी-परिवार भाषाओं में पूरी तरह से अलग करने के लिए विकसित किया गया है। हम चाहते हैं आज कॉल कि "वस्तु प्रतिनिधित्व" सी में)

यह परिभाषा तार्किक और बिटवाइज़ को एक ही मशीन-भाषा निर्देश का उपयोग नहीं करने की अनुमति देती है। यदि सी उस मार्ग पर चला गया था, तो हेडर दुनिया भर की फाइलों को कहेगा #define TRUE -1

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

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

लेकिन परिभाषित करने TRUEके रूप में 1और FALSEके रूप में 0बी में मतलब है कि पहचान true = ~ falseअब नहीं पहना है, और यह मजबूत टाइपिंग कि बिटवाइज़ और तार्किक अभिव्यक्ति को स्पष्ट करने के लिए अल्गोल अनुमति छोड़ दिया था। इसके लिए एक नए लॉजिकल-ऑपरेटर की आवश्यकता नहीं थी, और डिज़ाइनरों ने उठाया !, संभवतः क्योंकि बराबर-से-पहले से ही नहीं था !=, जो समान चिह्न के माध्यम से एक ऊर्ध्वाधर बार की तरह दिखता है। वे के रूप में ही सम्मेलन का पालन नहीं किया &&या ||क्योंकि न तो अभी तक अस्तित्व में।

यकीनन, उनके पास होना चाहिए: &बी में ऑपरेटर को डिज़ाइन के अनुसार तोड़ा गया है। बी और सी में, में 1 & 2 == FALSEभले ही 1और 2दोनों truthy मान रहे हैं, और वहाँ बी में तार्किक आपरेशन यही कारण है कि एक गलती सी आंशिक रूप से जोड़कर सुधारने की कोशिश की व्यक्त करने के लिए कोई सहज तरीका है &&और ||है, लेकिन समय पर मुख्य चिंता करने के लिए था अंत में काम करने के लिए शॉर्ट-सर्कुलेटिंग करें, और प्रोग्राम तेज चलाएं। इसका प्रमाण यह है कि कोई सत्य नहीं है ^^: 1 ^ 2एक सत्य मूल्य है भले ही उसके दोनों ऑपरेंड सत्य हैं, लेकिन यह शॉर्ट-सर्कुलेटिंग से लाभ नहीं उठा सकता है।


4
+1। मुझे लगता है कि यह इन ऑपरेटरों के विकास के आसपास एक बहुत अच्छा निर्देशित दौरा है।
स्टीव

BTW, साइन / परिमाण और किसी की पूरक मशीनों को भी अलग-अलग बिटवाइज़ बनाम तार्किक निषेध की आवश्यकता होती है, भले ही इनपुट पहले से ही गलत हो। ~0(सभी बिट्स सेट) नकारात्मक शून्य (या एक जाल प्रतिनिधित्व) का पूरक है। साइन / परिमाण ~0अधिकतम परिमाण के साथ एक ऋणात्मक संख्या है।
पीटर कॉर्ड्स

@PeterCordes आप बिल्कुल सही हैं। मैं सिर्फ दो-पूरक मशीनों पर ध्यान केंद्रित कर रहा था क्योंकि वे बहुत अधिक महत्वपूर्ण हैं। शायद यह एक फुटनोट के लायक है।
डेविस्लोर

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