วงแหวนเว็บ

neizod's speculation

insufficient data for meaningful answer

Quine (Self Printing Program) ในภาษา C

Saturday, July 12, 2014, 08:04 AM

หลายวันก่อนเปิดเจอโพสนี้ของคุณ @theppitak ที่ให้เขียนโปรแกรม quine ซึ่งเป็นโจทย์ปัญหาทางการเขียนโปรแกรมคอมพิวเตอร์ ที่ให้เราสร้างโค้ดที่เมื่อเรียกให้มันทำงานแล้ว ต้องได้ผลลัพธ์พิมพ์กลับออกมาเป็นโค้ดโปรแกรมต้นฉบับที่เราเขียนไป แน่นอนว่าการโกงโดยเปิดไฟล์โค้ดมาพิมพ์ไม่นับ

พูดง่ายๆ ว่าถ้าสมมติว่าโปรแกรมนั้นชื่อ self.c การสั่งคำสั่ง diff ครั้งสุดท้ายในโค้ดต่อไปนี้ต้องให้ค่าคืนมาเป็นว่า 2 ไฟล์มีเนื้อหาเหมือนกัน

$ gcc self.c
$ ./a.out > other.c
$ diff self.c other.c

เนื่องจากคุ้นๆ ว่าจะเคยเห็นคำถามแนวนี้ใน Ruby มาก่อนแล้ว ตอนแรกก็ไม่ได้คิดว่าจะลองทำหรอก แต่เท่าที่สังเกตแล้วจุดที่น่าจะเป็นปัญหาน่าจะมาจากเรื่อง escape string ซึ่งใน Python มันคงไม่ยุ่งยากเท่าไหร่ เพราะมี raw string และฟังก์ชั่น repr ไว้คอยจัดการปัญหา escape string อยู่แล้ว

แต่คิดไปคิดมา เอ่อ แล้วถ้าเป็นใน C (ที่ต้นทางเค้าสงสัย) นี่มันจะทำยังไงหว่า? เลยลงมือเขียนเล่นๆ จนได้ออกมาดังนี้

void main() {
  int i = 0, j = 0;
  char* x = "void main() {\n\tint i = 0, j = 0;\n\tchar* x = \"%s\";\n\twhile (x[i]) {\n\t\tif (x[i++] == '%%' && x[i++] == 's') {\n\t\t\twhile (x[j]) {\n\t\t\t\tswitch (x[j++]) {\n\t\t\t\t\tcase '\\n': putchar('\\\\'); putchar('n'); break;\n\t\t\t\t\tcase '\\t': putchar('\\\\'); putchar('t'); break;\n\t\t\t\t\tcase '\\\"': putchar('\\\\'); putchar('\"'); break;\n\t\t\t\t\tcase '\\\\': putchar('\\\\'); putchar('\\\\'); break;\n\t\t\t\t\tdefault: putchar(x[j-1]);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tputchar(x[i-1]);\n\t\t}\n\t}\n}\n";
  while (x[i]) {
    if (x[i++] == '%' && x[i++] == 's') {
      while (x[j]) {
        switch (x[j++]) {
          case '\n': putchar('\\'); putchar('n'); break;
          case '\t': putchar('\\'); putchar('t'); break;
          case '\"': putchar('\\'); putchar('"'); break;
          case '\\': putchar('\\'); putchar('\\'); break;
          default: putchar(x[j-1]);
        }
      }
    } else {
      putchar(x[i-1]);
    }
  }
}

ไม่ได้จับ C มาหลายปี หมดพลังไปเยอะกว่าจะคิดออก 555+

Revision notes:

  • April 12, 2016:

    เพิ่งรู้ว่าโจทย์แนวนี้มีชื่อโดยเฉพาะเลยว่า quine ประทับใจจนต้องเปลี่ยนจั่วหัว blog ตอนนี้ 55555

neizod

author