main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
Non, ce programme n'imprime pas have fun with unix ou quelque chose de ce genre ! Le lecteur est invité à essayer d'élucider ce programme (oui, il imprime quelque chose, mais quoi ?) la solution est donnée à la page suivante.
Voici les clés de la compréhension :
main() { printf(&1["\021%six\012\0"],(1)["have"]+"fun"-0x60);}
t[i]
est équivalent à i[t]
, on voit que 1["\021%six\012\0"]
est
équivalent à "\021%six\012\0"[1]
et (1)["have"]
à
"have"[1]
.
Donc &1["\021%six\012\0"]
est l'adresse du caractère %
dans la
chaîne "\021%six\012\0"
et "have"[1]
est le caractère 'a'
.
On peut donc réécrire le programme :
main() { printf("%six\012\0", 'a' + "fun" -0x60);}
\0
)
et le compilateur en met un à la fin de chaque chaîne littérale. Celui qui
est ici est donc inutile.
D'autre part, il existe une notation plus parlante pour le caractère de code
\012
(c'est à dire new line), il s'agit de la notation \n
.
Le programme peut donc se réécrire :
main() { printf("%six\n", 'a' + "fun" -0x60);}
'a'
a pour code ASCII 0x61, donc
'a' -0x60
est égal à 1.
Réécrivons le programme :
main() { printf("%six\n","fun" + 1); }
"fun" + 1
est l'adresse du caractère u dans la chaîne "fun"
,
le programme devient donc :
main() { printf("%six\n","un"); }il imprime donc
unix
.