सी कोड प्रतियोगिता 2006 को स्थगित कर दिया। कृपया sykes2.c की व्याख्या करें


974

यह C प्रोग्राम कैसे काम करता है?

main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}

यह (जैसा कि परीक्षण किया गया gcc 4.6.3) है। यह संकलित होने के समय को प्रिंट करता है। मेरे सिस्टम पर:

    !!  !!!!!!              !!  !!!!!!              !!  !!!!!! 
    !!  !!  !!              !!      !!              !!  !!  !! 
    !!  !!  !!              !!      !!              !!  !!  !! 
    !!  !!!!!!    !!        !!      !!    !!        !!  !!!!!! 
    !!      !!              !!      !!              !!  !!  !! 
    !!      !!              !!      !!              !!  !!  !! 
    !!  !!!!!!              !!      !!              !!  !!!!!!

स्रोत: sykes2 - एक लाइन में एक घड़ी , sykes2 लेखक संकेत

कुछ संकेत: डिफ़ॉल्ट रूप से कोई संकलन चेतावनी नहीं। के साथ संकलित -Wall, निम्नलिखित चेतावनी उत्सर्जित की जाती हैं:

sykes2.c:1:1: warning: return type defaults to int [-Wreturn-type]
sykes2.c: In function main’:
sykes2.c:1:14: warning: value computed is not used [-Wunused-value]
sykes2.c:1:1: warning: implicit declaration of function putchar [-Wimplicit-function-declaration]
sykes2.c:1:1: warning: suggest parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
sykes2.c:1:1: warning: suggest parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
sykes2.c:1:1: warning: control reaches end of non-void function [-Wreturn-type]

6
डीबग: प्रिंट्स printf("%d", _);की शुरुआत में जोड़ना main: pastebin.com/HHhXAYdJ
Corny

पूर्णांक, हर int
अनकैप्ड

18
क्या आपने संकेत पढ़ा है? ioccc.org/2006/sykes2/hint.text
nhahtdh

2
इसके अलावा पढ़ें stackoverflow.com/questions/10321196/…
Xofo

यदि आप इसे इस तरह चलाते हैं तो यह दुर्घटनाग्रस्त हो जाता है:./a.out $(seq 0 447)
एसएस ऐनी

जवाबों:


1819

आइए इसे डिफ्यूज़ करें।

इंडेंट:

main(_) {
    _^448 && main(-~_);
    putchar(--_%64
        ? 32 | -~7[__TIME__-_/8%8][">'txiZ^(~z?"-48] >> ";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1
        : 10);
}

इस गंदगी को हटाने के लिए चर का परिचय:

main(int i) {
    if(i^448)
        main(-~i);
    if(--i % 64) {
        char a = -~7[__TIME__-i/8%8][">'txiZ^(~z?"-48];
        char b = a >> ";;;====~$::199"[i*2&8|i/64]/(i&2?1:8)%8;
        putchar(32 | (b & 1));
    } else {
        putchar(10); // newline
    }
}

ध्यान दें कि -~i == i+1 क्योंकि twos- पूरक। इसलिए, हमारे पास है

main(int i) {
    if(i != 448)
        main(i+1);
    i--;
    if(i % 64 == 0) {
        putchar('\n');
    } else {
        char a = -~7[__TIME__-i/8%8][">'txiZ^(~z?"-48];
        char b = a >> ";;;====~$::199"[i*2&8|i/64]/(i&2?1:8)%8;
        putchar(32 | (b & 1));
    }
}

अब, ध्यान दें कि a[b]जैसा हैb[a] , और -~ == 1+फिर से लागू करें:

main(int i) {
    if(i != 448)
        main(i+1);
    i--;
    if(i % 64 == 0) {
        putchar('\n');
    } else {
        char a = (">'txiZ^(~z?"-48)[(__TIME__-i/8%8)[7]] + 1;
        char b = a >> ";;;====~$::199"[(i*2&8)|i/64]/(i&2?1:8)%8;
        putchar(32 | (b & 1));
    }
}

पुनरावृत्ति को एक पाश में बदलना और थोड़ा और सरलीकरण करना:

// please don't pass any command-line arguments
main() {
    int i;
    for(i=447; i>=0; i--) {
        if(i % 64 == 0) {
            putchar('\n');
        } else {
            char t = __TIME__[7 - i/8%8];
            char a = ">'txiZ^(~z?"[t - 48] + 1;
            int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
            if((i & 2) == 0)
                shift /= 8;
            shift = shift % 8;
            char b = a >> shift;
            putchar(32 | (b & 1));
        }
    }
}

यह प्रति वर्ण एक वर्ण आउटपुट करता है। हर 64 वें चरित्र में, यह एक नई रूपरेखा प्रस्तुत करता है। अन्यथा, यह आउटपुट करने के लिए क्या पता लगाने के लिए डेटा तालिकाओं की एक जोड़ी का उपयोग करता है, और या तो चरित्र 32 (एक स्थान) या चरित्र 33 (ए) को डालता है! ) । पहली तालिका ( ">'txiZ^(~z?") प्रत्येक वर्ण की उपस्थिति का वर्णन करने वाले 10 बिटमैप का एक सेट है, और दूसरी तालिका ( ";;;====~$::199") बिटमैप से प्रदर्शित करने के लिए उपयुक्त बिट का चयन करती है।

दूसरी तालिका

की दूसरी तालिका का परीक्षण करके शुरू करते हैं, int shift = ";;;====~$::199"[(i*2&8) | (i/64)];i/64पंक्ति संख्या (6 से 0) और हैi*2&8 8 iff i4, 5, 6 या 7 mod 8 है।

if((i & 2) == 0) shift /= 8; shift = shift % 8या तो उच्च ओक्टल अंक ( i%8= 0,1,4,5 के लिए) या i%8तालिका मूल्य के कम ऑक्टल अंक ( = 2,3,6,7 के लिए) का चयन करता है। पारी तालिका इस तरह से समाप्त होती है:

row col val
6   6-7 0
6   4-5 0
6   2-3 5
6   0-1 7
5   6-7 1
5   4-5 7
5   2-3 5
5   0-1 7
4   6-7 1
4   4-5 7
4   2-3 5
4   0-1 7
3   6-7 1
3   4-5 6
3   2-3 5
3   0-1 7
2   6-7 2
2   4-5 7
2   2-3 3
2   0-1 7
1   6-7 2
1   4-5 7
1   2-3 3
1   0-1 7
0   6-7 4
0   4-5 4
0   2-3 3
0   0-1 7

या सारणीबद्ध रूप में

00005577
11775577
11775577
11665577
22773377
22773377
44443377

ध्यान दें कि लेखक ने पहले दो टेबल प्रविष्टियों (डरपोक!) के लिए नल टर्मिनेटर का उपयोग किया था।

इसे सात-खंड के प्रदर्शन के बाद डिज़ाइन किया गया है 7 रिक्त स्थान है। तो, पहली तालिका में प्रविष्टियों को उन खंडों को परिभाषित करना होगा जो कि जलते हैं।

पहली तालिका

__TIME__प्रीप्रोसेसर द्वारा परिभाषित एक विशेष मैक्रो है। यह उस स्ट्रिंग स्थिरांक तक फैलता है जिसमें उस समय होता है जिस पर प्रीप्रोसेसर को फॉर्म में चलाया गया था "HH:MM:SS"। गौर करें कि इसमें ठीक 8 अक्षर हैं। ध्यान दें कि 0-9 में 57 के माध्यम से एएससीआईआई के 48 मान हैं और: एएससीआईआई का मूल्य 58 है। आउटपुट 64 वर्ण प्रति पंक्ति है, जिससे प्रति वर्ण 8 अक्षर निकलते हैं __TIME__

7 - i/8%8इस प्रकार उस का सूचकांक __TIME__वर्तमान में उत्पादन किया जा रहा है ( 7-जरूरत है क्योंकि हम iनीचे की ओर पुनरावृत्ति कर रहे हैं )। तो, tका चरित्र है__TIME__ आउटपुट होने ।

aइनपुट के आधार पर बाइनरी में निम्नलिखित को बराबर करना होता है t:

0 00111111
1 00101000
2 01110101
3 01111001
4 01101010
5 01011011
6 01011111
7 00101001
8 01111111
9 01111011
: 01000000

प्रत्येक संख्या एक बिटमैप है जो उन खंडों का वर्णन करता है जो हमारे सात-खंड प्रदर्शन में जलाए जाते हैं। चूंकि वर्ण सभी 7-बिट ASCII हैं, इसलिए उच्च बिट को हमेशा साफ़ किया जाता है। इस प्रकार, 7खंड तालिका में हमेशा रिक्त के रूप में प्रिंट होता है। दूसरी तालिका 7एस के साथ इस तरह दिखती है :

000055  
11  55  
11  55  
116655  
22  33  
22  33  
444433  

तो, उदाहरण के लिए, 4है 01101010(बिट्स 1, 3, 5, और 6 सेट) है, जो के रूप में प्रिंट

----!!--
!!--!!--
!!--!!--
!!!!!!--
----!!--
----!!--
----!!--

यह दिखाने के लिए कि हम वास्तव में कोड को समझते हैं, आइए इस तालिका के साथ आउटपुट को थोड़ा समायोजित करें:

  00  
11  55
11  55
  66  
22  33
22  33
  44

यह इनकोडेड है "?;;?==? '::799\x07"। कलात्मक उद्देश्यों के लिए, हम 64 अक्षरों में से कुछ को जोड़ेंगे (चूंकि केवल कम 6 बिट्स का उपयोग किया जाता है, यह आउटपुट को प्रभावित नहीं करेगा); यह देता है "?{{?}}?gg::799G"(ध्यान दें कि 8 वां वर्ण अप्रयुक्त है, इसलिए हम वास्तव में इसे जो चाहें बना सकते हैं)। हमारी नई तालिका को मूल कोड में लाना:

main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>"?{{?}}?gg::799G"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}

हमें मिला

          !!              !!                              !!   
    !!  !!              !!  !!  !!  !!              !!  !!  !! 
    !!  !!              !!  !!  !!  !!              !!  !!  !! 
          !!      !!              !!      !!                   
    !!  !!  !!          !!  !!      !!              !!  !!  !! 
    !!  !!  !!          !!  !!      !!              !!  !!  !! 
          !!              !!                              !!   

जैसा हमें उम्मीद थी। यह मूल के रूप में ठोस दिखने वाला नहीं है, जो बताता है कि लेखक ने उस तालिका का उपयोग करने के लिए क्यों चुना जो उसने किया था।


2
@ प्राह्नर - तकनीकी रूप से यह दोनों एक *( +
डीरेफेरेंस

18
@ Арт 30мЦарионов: लगभग 30 मिनट, लेकिन मैं वापस आ रहा हूं और इसे काफी हद तक संपादित कर रहा हूं। मैं सी का उपयोग करता हूं, और मैंने व्यक्तिगत हित के लिए कुछ IOCCC deobfuscations किया है (पहले मैंने जो किया था, सिर्फ व्यक्तिगत हित के लिए, यह सुंदर रेसर था )। यदि आप यह पूछना चाहते हैं कि यह कैसे काम करता है, तो मुझे उपकृत करने में खुशी होगी;)
nneonneo

5
@ Арт aмЦарионов: एक दिन के बारे में IIRC (रेअटरर ज्योमेट्री को समझने में लगने वाला समय भी मायने रखता है)। वह प्रोग्राम भी बहुत चालाक है, क्योंकि यह कोई कीवर्ड का उपयोग नहीं करता है
nnonneo

178
सी .. असेंबली लैंग्वेज की सारी शक्ति असेंबली लैंग्वेज की पठनीयता के साथ संयुक्त है
wim

6
इस नस में अधिक के लिए, डॉन लीबस द्वारा "ऑब्सफैकेटेड सी एंड अदर मिस्ट्रीज" देखें। यह Obfuscated C Contest प्रविष्टियों का विश्लेषण करके C तकनीक सिखाता है।
क्रिस एन

102

आइए इसे आसान पढ़ने के लिए प्रारूपित करें:

main(_){
  _^448&&main(-~_);
  putchar((--_%64) ? (32|-(~7[__TIME__-_/8%8])[">'txiZ^(~z?"-48]>>(";;;====~$::199")[_*2&8|_/64]/(_&2?1:8)%8&1):10);
}

तो, यह बिना किसी तर्क के चल रहा है, _ (पारंपरिक रूप से argc) 1main()पुनरावर्ती रूप से स्वयं को कॉल करेगा, -(~_)(नकारात्मक बिटवाइज़ नहीं _) के परिणाम से गुजर रहा है , इसलिए वास्तव में यह 448 रिक्रिएशन (केवल जहाँ) जाएगा_^448 == 0 ) होगा।

इसे लेते हुए, यह 7 64-वर्ण चौड़ी लाइनें (बाहरी टर्नरी स्थिति, और 448/64 == 7) प्रिंट करेगा । तो चलिए इसे फिर से साफ करते हैं:

main(int argc) {
  if (argc^448) main(-(~argc));
  if (argc % 64) {
    putchar((32|-(~7[__TIME__-argc/8%8])[">'txiZ^(~z?"-48]>>(";;;====~$::199")[argc*2&8|argc/64]/(argc&2?1:8)%8&1));
  } else putchar('\n');
}

अब, 32ASCII स्थान के लिए दशमलव है। यह या तो एक स्पेस प्रिंट करता है या '!' (33 'है!', इसलिए &1अंत में ' ')। चलो बीच में बूँद पर ध्यान दें:

-(~(7[__TIME__-argc/8%8][">'txiZ^(~z?"-48]) >>
     (";;;====~$::199"[argc*2&8|argc/64]) / (argc&2?1:8) % 8

जैसा कि एक अन्य पोस्टर में कहा गया है, __TIME__कार्यक्रम के लिए संकलन समय है, और एक स्ट्रिंग है, इसलिए कुछ स्ट्रिंग अंकगणित चल रहे हैं, साथ ही एक सरणी सबस्क्रिप्ट का द्विदिश होने का फायदा उठा रहे हैं: [a] b [a] के समान है चरित्र सरणियों के लिए।

7[__TIME__ - (argc/8)%8]

यह पहले 8 वर्णों में से एक का चयन करेगा __TIME__। यह तब अनुक्रमित किया जाता है [">'txiZ^(~z?"-48](0-9 वर्ण 48-57 दशमलव हैं)। इस स्ट्रिंग के पात्रों को उनके ASCII मूल्यों के लिए चुना जाना चाहिए था। इसी प्रकार का ASCII कोड हेरफेर अभिव्यक्ति के माध्यम से जारी है, जिसके परिणामस्वरूप या तो '' या '' का मुद्रण होता है! चरित्र के ग्लिफ़ के भीतर स्थान के आधार पर।


49

अन्य समाधानों के साथ जोड़ना, -~xबराबर है x+1क्योंकि ~xइसके बराबर है (0xffffffff-x)। यह (-1-x)2s के पूरक के बराबर है , ऐसा ही -~xहै -(-1-x) = x+1


5
दिलचस्प। मैं कुछ समय के लिए जाना जाता है कि ~ x == -x - 1, लेकिन मुझे इसके पीछे गणितीय तर्क नहीं पता था।
अप्रोचडार्कनेसफिश

3
आई, कोल, (-1 एक्स) (-x-1) के समान है, आपको इसे "ठीक" करने की आवश्यकता नहीं है !!
थॉमस सॉन्ग

7
यही कारण है कि अगर कोई -1338 है, तो वे 1337 नहीं हैं।
एंड्रयू माओ

4

मैंने मोडुलो अंकगणित को जितना संभव हो उतना दूर नहीं किया और फिर से हटा दिया

int pixelX, line, digit ;
for(line=6; line >= 0; line--){
  for (digit =0; digit<8; digit++){
    for(pixelX=7;pixelX > 0; pixelX--){ 
        putchar(' '| 1 + ">'txiZ^(~z?"["12:34:56"[digit]-'0'] >> 
          (";;;====~$::199"[pixel*2 & 8  | line] / (pixelX&2 ? 1 : 8) ) % 8 & 1);               
    }
  }
  putchar('\n');
}

इसे थोड़ा और विस्तारित करना:

int pixelX, line, digit, shift;
char shiftChar;
for(line=6; line >= 0; line--){
    for (digit =0; digit<8; digit++){
        for(pixelX=7;pixelX >= 0; pixelX--){ 
            shiftChar = ";;;====~$::199"[pixelX*2 & 8 | line];
            if (pixelX & 2)
                shift = shiftChar & 7;
            else
                shift = shiftChar >> 3;     
            putchar(' '| (">'txiZ^(~z?"["12:34:56"[digit]-'0'] + 1) >> shift & 1 );
        }

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