2013-10-10 12 views
9

OK, morderò. Un answer del popolarissimo Why does the C preprocessor interpret the word "linux" as the constant "1"? questione afferma chePerché il Korn oneliner del 1987 stampa unix?

main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}` 

stampe "unix", ma per ragioni che non hanno assolutamente nulla a che fare con l'ortografia del nome di macro.

ho letto http://www.ioccc.org/1987/korn.hint ma penso abbastanza più in dettaglio aiuterebbe unobfuscating questo :)

+5

Questa "domanda" presenta un puzzle, non una domanda. –

+3

@EricPostpischil Ora un puzzle può mettere in discussione le persone, e se le persone sono perplesse, tendono a fare domande. – glglgl

risposta

12

unix è 1 a causa di un #define implicito nel compilatore o nell'ambiente di runtime.

Così, sia perché a[b] == b[a] == *(a + b) e quindi 1["xy"] == "xy"[1], si ottiene:

  • &unix["\021%six\012\0"] punti a "%six\012\0"
  • (unix)["have"] = "have"[1] = 'a',
  • "'a'+"fun"-0x60" = "fun" + 1 = "un".

Questo ti porta a printf("%six\012\0", "un"); che fa chiaramente stampa "unix\012", \012 essendo un'interruzione di linea (la stessa di \n).

Se unix non è definito, e. g.su un sistema Windows, si ottiene un errore.

Se unix era 0 (che può sempre essere il modo su un sistema pulito?), Si ottiene

printf("\012%six\n", 'h'+"fun"-0x60) 

dove il secondo argomento è "fun"+8, indicando Nirvana e che porta a un comportamento indefinito.

4

Normalmente penso che dovrebbe stampare "unix" solo quando compilato nell'ambito di un sistema Unix-like.

Questo perché su tali sistemi, unix è un predefinito macro con un valore di 1.

Come tale, essa si traduce come:

main() { printf(&1["\021%six\012\0"], (1)["have"]+"fun"-0x60); } 

Re-ordinato di disporre del int[array] sciocchezze, otteniamo:

main() { printf(&"\021%six\012\0"[1], "have"[1] + "fun"-0x60); } 

possiamo ignorare il \021 dal momento che è saltato (io basta sostituirlo con un ?) e tradurre lo \012 in \n:

main() { printf(&"?%six\n\0"[1], 'a' + "fun" - 0x60); } 
main() { printf( "%six\n",  0x61 + "fun" - 0x60); } 

che dà:

main() { printf("%six\n", "un"); } 

Nota: mi è stato ri-solving come sono andato (soprattutto la seconda parte), ma la prima volta che l'ho visto ho bisogno di due suggerimenti per capire anche la spiegazione:

  • unix significa 1
  • int[array] è una notazione reale che il compilatore accetta.