984 votes

Obfuscated C Code Contest 2006. Veuillez expliquer sykes2.c

Comment cela C programme de travail?

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

Il compile comme il est (testé sur gcc 4.6.3). Il imprime le temps lors de la compilation. Sur mon système:

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

Source: sykes2 - Une horloge dans une ligne, sykes2 auteur conseils

Quelques conseils: Pas de compiler des mises en garde par défaut. Compilé avec -Wall, les mises en garde suivantes sont émises:

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]

1830voto

nneonneo Points 56821

Nous allons de dissimuler.

Indentation:

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

L'introduction de variables de démêler ce gâchis:

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
    }
}

Notez que -~i == i+1 car des deux-complément de. Par conséquent, nous avons

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));
    }
}

Maintenant, notez qu' a[b] est le même que b[a], et d'appliquer l' -~ == 1+ de changer à nouveau:

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));
    }
}

La conversion de la récursivité à une boucle et de se faufiler dans un peu plus de simplification:

// 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));
        }
    }
}

Cette fonction génère un personnage par itération. Tous les 64e de caractère, elle génère un saut de ligne. Sinon, il utilise une paire de tables de données à la figure ce qu'à la sortie, et met l'un des personnages 32 (espace) ou le caractère de 33 !). Le premier tableau (">'txiZ^(~z?") est un ensemble de 10 bitmaps décrire l'apparence de chaque personnage, et la seconde table (";;;====~$::199") sélectionne le bit correspondant à l'affichage de l'image bitmap.

La seconde table

Commençons par l'examen de la deuxième table, int shift = ";;;====~$::199"[(i*2&8) | (i/64)];. i/64 est le numéro de la ligne (6 à 0) et i*2&8 8 iff i 4, 5, 6 ou 7 mod 8.

if((i & 2) == 0) shift /= 8; shift = shift % 8 sélectionne soit le haut chiffre octal ( i%8 = 0,1,4,5) ou le faible chiffre octal ( i%8 = 2,3,6,7) de la valeur de la table. La maj de la table finit par ressembler à ceci:

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

ou sous forme de tableau

00005577
11775577
11775577
11665577
22773377
22773377
44443377

Notez que l'auteur a utilisé le terminateur null pour les deux premières entrées de la table (sournois!).

Ceci est conçu d'après un à sept segments d'affichage, avec 7s comme des blancs. Ainsi, les entrées dans le premier tableau doit définir les segments être éclairé.

La première table

__TIME__ est un spécial macro définie par le préprocesseur. Il se développe à une constante de chaîne contenant l'heure à laquelle le préprocesseur a été exécuté, sous la forme "HH:MM:SS". Observer qu'il contient exactement 8 caractères. Notez que 0-9 ont des valeurs ASCII 48 par 57 : a la valeur ASCII 58. La sortie est de 64 caractères par ligne, de sorte que les feuilles de 8 caractères par caractères d' __TIME__.

7 - i/8%8 est donc l'indice d' __TIME__ qui est actuellement en cours de sortie ( 7- est nécessaire parce que nous sommes une itération i à la baisse). Donc, t est le caractère de l' __TIME__ en cours de sortie.

a finit par égaler le suivant en binaire, en fonction de l'entrée t:

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

Chaque numéro est un bitmap décrivant les segments allumés dans nos sept segments d'affichage. Car les personnages sont tous ASCII 7 bits, le bit élevé est toujours désactivée. Ainsi, 7 dans le segment de la table de toujours s'imprime comme un vide. La deuxième table ressemble à ceci avec l' 7s comme blancs:

000055  
11  55  
11  55  
116655  
22  33  
22  33  
444433  

Ainsi, par exemple, 4 est 01101010 (les bits 1, 3, 5, et 6), qui s'imprime comme

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

Montrer que nous sommes vraiment à comprendre le code, nous allons régler la sortie un peu avec ce tableau:

  00  
11  55
11  55
  66  
22  33
22  33
  44

C'est codée en tant que "?;;?==? '::799\x07". Pour artistiques, nous allons ajouter de 64 à quelques-uns des caractères (puisque seule la faible 6 bits sont utilisés, ce qui n'affecte pas la sortie), ce qui permet d' "?{{?}}?gg::799G" (à noter que la 8ème caractère est utilisé, alors, nous pouvons faire ce que nous voulons). Mise en application de notre nouvelle table dans le code d'origine:

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

nous obtenons

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

tout comme nous nous y attendions. Ce n'est pas aussi solide à la recherche de l'original, ce qui explique pourquoi l'auteur a choisi d'utiliser le tableau qu'il a fait.

103voto

chmeee Points 2777

Voyons ce format pour une lecture plus facile:

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

Ainsi, l'exécution d'elle sans arguments, _ (argc conventionnellement) 1. main() sera récursivement appel lui-même, le résultat le passage de l' -(~_) (négatif not au niveau du bit d' _), si vraiment ça va aller 448 récurrences (Seule condition où _^448 == 0).

De prendre, il va imprimer 7 64 caractères larges lignes (que l'extérieur de la condition ternaire, et 448/64 == 7). Donc, nous allons réécrire un peu plus propre:

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');
}

Maintenant, 32 est décimales en vue de l'ASCII de l'espace. Il imprime un espace ou un '!' (33,'!', d'où le '&1' à la fin). Concentrons-nous sur la goutte dans le milieu:

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

Comme une autre affiche a déclaré, __TIME__ est le moment de la compilation du programme, et est une chaîne, donc il y a une chaîne de caractères arithmétiques de passe, ainsi que de tirer profit d'un indice de tableau étant bidirectionnel: a[b] est le même que le b[a] pour des tableaux de caractères.

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

Cela permet de sélectionner l'un des 8 premiers caractères en __TIME__. C'est ensuite indexé dans [">'txiZ^(~z?"-48] (de 0 à 9 caractères sont 48-57 décimal). Les caractères de cette chaîne doit avoir été choisis pour leurs valeurs ASCII. Ce même caractère de code ASCII de la manipulation continue à travers l'expression, le résultat de l'impression d'un ' ou '!' en fonction de l'emplacement dans le caractère du glyphe.

49voto

Thomas Song Points 561

Les ajouter aux autres solutions, -~x est égal à x+1 car ~x est équivalent à (0xffffffff-x). C'est l'équivalent d' (-1-x) en 2s complément, afin -~x est -(-1-x) = x+1.

6voto

Lefteris E Points 1523

J'ai de-obscurci l'arithmétique modulo autant que je le pouvais et enlevé le reccursion

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');
}

De l'élargir un peu plus:

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');
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X