Signature email jaman kuliah

Dulu waktu kuliah, saya punya signature email seperti ini:

main(i){putchar((i-1)["Xme]i_l"]+(i++))&&(8-i)&&main(i);}


Ternyata masih ada beberapa orang yang ingat, dan masih banyak yang penasaran apa artinya (cuma satu kata: Yohanes) dan  kok bisa muncul seperti itu?

Pertama, menurut standar C lama, sebuah fungsi tanpa kembalian akan mengembalikan sebuah int, dan parameter yang tanpa tipe juga adalah sebuah int, jadi fungsi di atas sama dengan:

int main(int i){
    putchar((i-1)["Xme]i_l"]+(i++))
    &&(8-i)&&
    main(i);
}

Perhatikan juga bahwa di C, sifat operator && adalah short circuit, artinya dalam A() && B() jika A() mengembalikan false, maka B tidak dieksekusi:

#include <stdio.h>

int A() {
    printf("Fungsi A dipanggil\n");
    return 0;
}

int B() {
    printf("Fungsi B dipanggil\n");
    return 1;
}

int main(int argc, char *argv[])
{
    if (A() && B()) {
        printf("A dan B mengembalikan TRUE\n");
    }
    return 0;
}

Bagian main di atas sama saja dengan ini:

#include <stdio.h>

int main(int argc, char *argv[])
{
    if (A()) {
        if (B()) {
            printf("A dan B mengembalikan TRUE\n");
        }
    }
    return 0;
}

Jadi kode signature saya bisa dijadikan if juga seperti ini:

int main(int i){
    if (putchar((i-1)["Xme]i_l"]+(i++))) {
        if (8-i) {
            if (main(i)) {
            }
        }
    }
}

Perhatikan beberapa bisa diperjelas, misalnya (8-i) akan true jika (8-i) !=0, atau selama i != 8. Karena if (main()) kosong, maka bisa dihilangkan if-nya.

int main(int i){
    if (putchar((i-1)["Xme]i_l"]+(i++))) {
        if (i!=8) {
            main(i);
        }
    }
}

Di C, sebuah array adalah sebuah pointer dan sebuah string adalah array of characters. Di C:

int *array = (int *)malloc(sizeof(int)*10);
int index = 1;
array[index] = 10;
//syntax array access di atas sama dengan:
*(array + index) = 10;
//penjumlahan sifatnya komutatif
*(index + array) = 10;
//jadi ini juga sama:
index[array] = 10;

Untuk lebih jelasnya, string saya keluarkan, dan notasinya diperbaiki:

const char *str = "Xme]i_l";
int main(int i){
    if (putchar(str[i-1]+(i++))) {
        if (i!=8) {
            main(i);
        }
    }
}

Kita lihat fungsi putchar di manual:

fputc, fputs, putc, putchar, puts – output of characters and strings

Di bagian return value:

fputc(), putc() and putchar() return the character written as an unsigned char cast to an int or EOF on
error.

Catatan: karena fungsi putchar tidak dideklarasikan, dan saya tidak menginclude apapun, maka dianggap kembaliannya int, dan ada warning dari compiler.

Dalam kasus saya, putchar ini akan selalu mengembalikan 1, karena saya memprint satu karakter setiap waktu. Jadi kita sederhanakan lagi:

const char *str = "Xme]i_l";
int main(int i){
    putchar(str[i-1]+(i++));
    if (i!=8) {
       main(i);
    }
}

Operator ++ (post increment) akan dilakukan setelah sebuah ekspresi, jadi dalam kasus ini bisa disederhanakan:

const char *str = "Xme]i_l";
int main(int i){
   putchar(str[i-1]+i);
   i++;
   if (i!=8) {
     main(i);
   }
}

Sekarang ke bagian “magic”-nya. Di sistem operasi Windows, Linux atau POSIX yang lain, ketika program dijalankan, maka program dalam C akan menerima jumlah parameter dan isi parameternya

int main(int argc, char *argv[])

Jika kita deklarasikan tanpa argv, maka hanya jumlah parameternya yang kita dapatkan. Meskipun biasanya namanya argc dan argv, nama parameternya tentunya boleh apa saja

int main(int jumlah_argumen)

Jika program dijalankan tanpa parameter, maka jumlah argumennya adalah 1, yaitu nama program saat ini (yang tidak kita pedulikan di program ini). Jadi sebenarnya program tersebut dipanggil dengan

main(1);

Perhatikan bahwa “main” adalah sebuah fungsi di C, dan seperti fungsi apapun, bisa dipanggil bebas. Dalam kasus ini, saya memanggil (rekursif) main, dengan nilai i yang ditambahkan terus.

Jika ingin kode yang sangat jelas tiap langkahnya seperti ini:

#include <stdio.h>

const char *str = "Xme]i_l";
int main(int i){
  printf("\ni = %d\n", i);
  printf("str[i-1] = %c +%d = %c\n", str[i-1], i, str[i-1] + i);
  putchar(str[i-1]+i);
  i++;
  if (i!=8) {
    main(i);
  }
}

Dan outputnya:

yohanes@intel-nuc:~$ ./a.out

i = 1
str[i-1] = X +1 = Y
Y
i = 2
str[i-1] = m +2 = o
o
i = 3
str[i-1] = e +3 = h
h
i = 4
str[i-1] = ] +4 = a
a
i = 5
str[i-1] = i +5 = n
n
i = 6
str[i-1] = _ +6 = e
e
i = 7
str[i-1] = l +7 = s

Demikian keisengan jaman kuliah dulu. Sekedar tambahan: dulu terinspirasi dari International Obfuscated C Code Contest, kode saya ini sangat sederhana dibandingkan para pemenang IOCCC.

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *