C में >>> = ऑपरेटर क्या है?


294

एक सहकर्मी द्वारा एक पहेली के रूप में दिया गया, मैं यह पता नहीं लगा सकता कि यह सी कार्यक्रम वास्तव में कैसे संकलित करता है और चलता है। यह >>>=ऑपरेटर और अजीब 1P1शाब्दिक क्या है? मैंने क्लैंग और जीसीसी में परीक्षण किया है। कोई चेतावनी नहीं है और आउटपुट "???" है

#include <stdio.h>

int main()
{
    int a[2]={ 10, 1 };

    while( a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ] )
        printf("?");

    return 0;
}

36
उनमें से कुछ डिग्राफ हैं
जुआनकोपंजा

12
@ केय, इस मामले में नहीं::> =] फिर एक [...] >> = एक [...]
एड्रियानो रेपेती

6
@Marc मुझे नहीं लगता कि यह ">>> =" हो सकता है क्योंकि यह संकलन नहीं होगा, हालांकि उपरोक्त कोड वास्तव में संकलन करता है।
22 अक्टूबर को CustomCalc

21
0x.1P1एक प्रतिपादक के साथ एक हेक्साडेसिमल शाब्दिक है। 0x.1संख्या हिस्सा है, या 1/16 यहाँ। 'P' के बाद की संख्या दो की शक्ति से गुणा होती है। तो 0x.1p1वास्तव में 1/16 * 2, या 1/8 है। और अगर आप के बारे में सोच रहे थे, तो 0xFULLहै कि बस है 0xF, और ULLके लिए एक प्रत्यय हैunsigned long long
jackarms

71
सी सिंटैक्स - पंडितों और सामान्य ज्ञान प्रेमियों के लिए अंतहीन सामग्री, लेकिन अंततः यह सब महत्वपूर्ण नहीं है।
केरेक एसबी

जवाबों:


468

रेखा:

while( a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ] )

शामिल द्वि आलेख :> और <:है, जो करने के लिए अनुवाद करते हैं ]और [क्रमशः, तो यह करने के लिए बराबर है:

while( a[ 0xFULL?'\0':-1 ] >>= a[ !!0X.1P1 ] )

शाब्दिक के 0xFULLरूप में ही है 0xF(जो हेक्स के लिए है 15); ULLबस निर्दिष्ट करता है कि यह एक है unsigned long longशाब्दिक । किसी भी मामले में, एक बूलियन के रूप में यह सच है, इसलिए इसका 0xFULL ? '\0' : -1मूल्यांकन करता है '\0', जो एक चरित्र शाब्दिक है जिसका संख्यात्मक मान बस है 0

इस बीच, 0X.1P1एक हेक्साडेसिमल फ्लोटिंग पॉइंट शाब्दिक है जो 2/16 = 0.125 के बराबर है। किसी भी मामले में, गैर-शून्य होने के नाते, यह एक बूलियन के रूप में भी सच है, इसलिए इसे दो बार !!फिर से पैदा करना नकारात्मक है 1। इस प्रकार, संपूर्ण चीज़ सरल हो जाती है:

while( a[0] >>= a[1] )

ऑपरेटर >>=एक यौगिक असाइनमेंट है जो बिट ऑपरेंड द्वारा दिए गए बिट्स की संख्या से अपने बाएं ऑपरेंड को सही-सही बदलता है, और परिणाम देता है। इस मामले में, सही ऑपरेंड का a[1]हमेशा मूल्य होता है 1, इसलिए यह इसके बराबर है:

while( a[0] >>= 1 )

या, समतुल्य:

while( a[0] /= 2 )

का प्रारंभिक मूल्य a[0]है। एक बार सही तरीके से शिफ्ट करने के बाद, यह 5 हो जाता है, फिर (नीचे चक्कर) 2, फिर 1 और अंत में 0, जिस बिंदु पर लूप समाप्त होता है। इस प्रकार, लूप बॉडी को तीन बार निष्पादित किया जाता है।


18
आप पर विस्तृत कृपया सकते Pमें 0X.1P1
- एसई बुराई है

77
@Ay: यह वैसा ही eहै 10e5, जैसा कि आपको pहेक्साडेसिमल शाब्दिक के लिए उपयोग करना है क्योंकि eहेक्साडेसिमल अंक है।
डिट्रिच एप्प

9
@ कै: हेक्स फ्लोट लिटरल्स C99 का हिस्सा हैं, लेकिन GCC उन्हें C ++ कोड में भी स्वीकार करता है । डिट्रिच नोट के रूप में, सामान्य वैज्ञानिक फ्लोट नोटेशन की pतरह, मंटिसा और प्रतिपादक को अलग करता eहै; एक अंतर यह है कि, हेक्स फ्लोट्स के साथ, घातीय भाग का आधार 10 के बजाय 2 है, इसलिए 0x0.1p10x0.1 = 1/16 गुना 2¹ = 2 के बराबर होता है (किसी भी मामले में, यहां कोई भी मायने नहीं रखता है; कोई भी गैर-शून्य; मूल्य वहाँ भी समान रूप से अच्छी तरह से काम करेगा।)
इल्मरी करोनन

6
@chux: जाहिरा तौर पर, यह इस बात पर निर्भर करता है कि कोड C के रूप में संकलित किया गया है (जैसा कि इसे मूल रूप से टैग किया गया था) C ++। लेकिन मैंने "शाब्दिक" के बजाय "वर्ण शाब्दिक" कहने के लिए पाठ को ठीक किया char, और एक विकिपीडिया लिंक जोड़ा। धन्यवाद!
इल्मरी करोनें

8
अच्छी कमी।
कोरी

69

यह कुछ बल्कि अस्पष्ट कोड है , जिसमें क्रमशः डिग्राफ शामिल हैं , <:और :>जो क्रमशः [और इसके लिए वैकल्पिक टोकन ]हैं। सशर्त ऑपरेटर का कुछ उपयोग भी है । वहाँ भी एक है बिट स्थानांतरण ऑपरेटर , सही पारी काम >>=

यह एक अधिक पठनीय संस्करण है:

while( a[ 0xFULL ? '\0' : -1 ] >>= a[ !!0X.1P1 ] )

और इससे भी अधिक पठनीय संस्करण, []उनके द्वारा हल किए गए मानों के लिए भावों की जगह :

while( a[0] >>= a[1] )

प्रतिस्थापित करना a[0]और a[1]उनके मूल्यों के लिए यह पता लगाना आसान होना चाहिए कि लूप क्या कर रहा है, अर्थात:

int i = 10;
while( i >>= 1)

जो कि प्रत्येक पुनरावृति में क्रम से (पूर्णांक) विभाजन 2 का प्रदर्शन कर रहा है, जो अनुक्रम का निर्माण कर रहा है 5, 2, 1


मैंने इसे नहीं चलाया - क्या यह ओपी को प्राप्त होने के ????बजाय उत्पादन नहीं करेगा ???? (हुह।) codepad.org/nDkxGUNi उत्पादन करता है???
usr2564301

7
@ जोंगवेयर 10 पहले पुनरावृत्ति पर विभाजित हो गया। इसलिए लूप द्वारा मूल्यांकन किए जा रहे मान 5, 2, 1 और 0. हैं, इसलिए यह केवल 3 बार प्रिंट करता है।
मिस्टिकएक्सजी

42

चलो बाएं से दाएं अभिव्यक्ति के माध्यम से चलते हैं:

a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ]

पहली बात जो मैंने नोटिस की, वह यह है कि हम टर्नेरी ऑपरेटर के उपयोग से उपयोग कर रहे हैं ?। तो उपसर्ग:

0xFULL ? '\0' : -1

कह रहा है, "अगर 0xFULLगैर शून्य, वापसी है '\0', अन्यथा -10xFULLसाथ हेक्साडेसिमल शाब्दिक है अहस्ताक्षरित लंबे समय से लंबे प्रत्यय - जिसका अर्थ यह प्रकार का एक हेक्साडेसिमल शाब्दिक है unsigned long longकि वास्तव में बात करें, क्योंकि ऐसा नहीं करता। 0xFएक नियमित पूर्णांक के अंदर फिट कर सकते हैं।

साथ ही, टर्नरी ऑपरेटर दूसरे और तीसरे शब्दों के प्रकारों को उनके सामान्य प्रकार में परिवर्तित करता है। '\0'तब परिवर्तित किया जाता है int, जो कि बस है 0

का मान 0xFशून्य से बड़ा है, इसलिए यह गुजरता है। अब अभिव्यक्ति बन जाती है:

a[ 0 :>>>=a<:!!0X.1P1 ]

अगला, :>एक डिग्राफ है । यह एक निर्माण है जो कि विस्तार करता है ]:

a[0 ]>>=a<:!!0X.1P1 ]

>>=हस्ताक्षरित सही शिफ्ट ऑपरेटर है, हम aइसे स्पष्ट करने के लिए बाहर से अंतरिक्ष कर सकते हैं ।

इसके अलावा, <:एक डिग्राफ है जिसका विस्तार है [:

a[0] >>= a[!!0X.1P1 ]

0X.1P1एक घातांक के साथ एक हेक्साडेसिमल शाब्दिक है। लेकिन मूल्य का कोई फर्क नहीं पड़ता, जो !!कुछ भी गैर-शून्य है वह सच है। 0X.1P1है 0.125जो गैर-शून्य है, तो यह हो जाता है:

a[0] >>= a[true]
-> a[0] >>= a[1]

>>=पर हस्ताक्षर किए सही पारी ऑपरेटर है। यह ऑपरेटर के दाईं ओर के अपने बिट्स को आगे की ओर मोड़कर अपने बाएं ऑपरेंड के मूल्य को बदल देता है। 10बाइनरी में है 1010। तो यहाँ कदम हैं:

01010 >> 1 == 00101
00101 >> 1 == 00010
00010 >> 1 == 00001
00001 >> 1 == 00000

>>=इसके संचालन का परिणाम देता है, इसलिए जब तक शिफ्टिंग a[0]हर बार गैर-शून्य रहती है तब तक इसके बिट्स को एक-एक करके दाएं से शिफ्ट किया जाता है। चौथा प्रयास वह a[0]होता है 0, जहां लूप कभी दर्ज नहीं होता है।

परिणामस्वरूप, ?तीन बार मुद्रित किया जाता है।


3
:>एक है संयुक्ताक्षर , नहीं एक trigraph। यह प्रीप्रोसेसर द्वारा संभाला नहीं गया है, यह बस एक टोकन समकक्ष के रूप में मान्यता प्राप्त है ]
कीथ थॉम्पसन

@KeithThompson धन्यवाद
0x499602D2

1
टर्नेरी ऑपरेटर ( ?:) में एक प्रकार है जो दूसरे और तीसरे शब्दों का सामान्य प्रकार है। पहला शब्द हमेशा एक सशर्त होता है और इसका एक प्रकार होता है bool। चूंकि दूसरे और तीसरे दोनों शब्दों intमें टाइपरी ऑपरेशन का परिणाम होगा int, न कि unsigned long long
कोरी

2
@KeithThompson इसे प्रीप्रोसेसर द्वारा संभाला जा सकता है। प्रीप्रोसेसर को digraphs के बारे में जानना होगा क्योंकि #और ##digraphs रूप हैं; प्रारंभिक अनुवाद के चरणों के दौरान डिग्राफ को गैर-डिग्राफ में अनुवाद करने से कुछ भी नहीं होता है
एमएम

@MattMcNabb यह एक लंबा समय रहा है क्योंकि मुझे यह जानना था, लेकिन IIRC अन्य आवश्यकताओं के परिणामस्वरूप, डिग्राफ को अपने डिग्राफ रूप में रहना पड़ता है, जब तक कि पीपी-टोकन टोकन में परिवर्तित नहीं हो जाते हैं (अनुवाद चरण की शुरुआत में सही) 7)।
zwol
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.