Sonntag, 21. November 2010

Ein Quine mit C#

Ein Quine ist ein Programm, welches seinen kompletten eigenen Quellcode als Ausgabe ausgibt.
Lautet der Quellcode also beispielsweise

class Quine
{
    static void Main()
    {
        System.Console.WriteLine("Dies ist (noch) kein Quine.");
    }
}

müsste das Programm genau diesen Text ausgeben.
Je nachdem, wie erfahren man mit Problemen aus diesem Bereich ist, wird einem die Aufgabe, ein Quine zu schreiben, vielleicht als einfach, schwer oder sogar unmöglich vorkommen.
(Für theoretisch interessierte: In allen "höheren" Programmiersprachen, also C, C#, Java etc. ist sogar garantiert, dass Quines existieren müssen. Denn all diese Sprachen sind Turing - vollständig, und in Turing - vollständigen Sprachen lässt sich ein Quine realisieren.)
Geht man ganz naiv an die Sache ran, könnte man vielleicht vermuten, das Problem wäre ganz schnell gelöst.
Man druckt zuerst den Code bis zur Zeile mit WriteLine(), dann diese Zeile und schließlich den Rest bis zur abschließenden Klammer.
Aber Moment! Die Aufgabenstellung besagt, dass der komplette Quellcode gedruckt werden soll, es müssen also auch alle WriteLine() Anweisungen gedruckt werden.
Schreibt man beispielsweise
string test = "abc";
und gibt diese Zeile dann mittels WriteLine() aus
WriteLine("string test = \"abc\";");
, muss im nächsten Schritt dann auch diese Zeile ausgedruckt werden.
Damit so keine Endlosrekursion entsteht, besteht der Trick darin, den auszugebenden Code in einem String zu speichern und dann nur diesen String auszugeben.
Weiterhin wird noch ausgenutzt, dass in C# in der WriteLine() - Methode Platzhalter benutzt werden können, welche dann später ersetzt werden.
Ich zeige jetzt einfach den Code eines von mir geschriebenen funktionierenden Quines, die abstrakten Forderungen von oben werden so vielleicht am besten deutlich:

class Quine
{
    static void Main(string[] args)
    {
        string s = "class Quine {3} {0} {3} static void Main(string[] args) {3} {0} {3} string s = {2}{1}{2}; {3} System.Console.WriteLine(s, System.Convert.ToChar(123), s, System.Convert.ToChar(34), System.Environment.NewLine, System.Convert.ToChar(125)); {3} {4} {3} {4}";
        System.Console.WriteLine(s, System.Convert.ToChar(123), s, System.Convert.ToChar(34), System.Environment.NewLine, System.Convert.ToChar(125));
    }
}

Kommentare:

  1. macht man das wirklich so? normalerweise nutzt man doch dafür reflection und andere methoden, um einfacher da ran zu kommen. ich kopiere doch nicht die ganze klassendefinition in einen string und geb den aus^^

    AntwortenLöschen
  2. Hmm, hacker machen sich ja einen Spaß daraus, in einer gegebenen Sprache das kürzest mögliche Quine zu schreiben. Von daher wird die Klassendefinition ja möglichst kurz sein, ich würde sagen auf ähnliche Weise wie oben lassen sich in C# die kürzesten Quines schreiben. Mit Reflection lassen sich prinzipiell auch Quines erstellen, oft wird der Zugriff jedoch aus Sicherheitsgründen eingeschränkt. Ich hätte jetzt im Moment aber auch gar keine Idee, wie du es schnell auf diese Weise bewerkstelligen wolltest. Kannst ja gerne mal was posten ;-)

    AntwortenLöschen