Digital > Fefes Blog 2.0 > b98ee7a7
  Leserreporter: Wer schöne Verschwörungslinks für mich hat: ab an felix-bloginput (at) fefe.de!
[zurück][ältere Posting][neuere Posting]  Montag, 24 Dezember 2007 | Blog: 3 | No: 10801     feed-image

Wie kann man das besser machen?

Hier mal wieder eine Sache für Bitpfriemel-C-Hacker. Ich hacke gerade an einer SMB-Implementation herum. SMB ist ein Binärprotokoll, und ich bin ein fauler Sack, also implementiere ich das kurz gesagt so, dass ich da konstante Arrays den Hex-Dumps der gewünschten Antworten drin deklariere, und dann an den entsprechenden Offsets die Werte eintrage, die da hingehören. Ich habe die Offsets dann immer von Hand nachgezählt, und der Code sieht jetzt entsprechend aus. Wenn jemand diesen Code prüfen will, muss er im Grunde alle meine magischen Offsets von Hand nachzählen, ob die auch richtig sind. Kurz gesagt: völlig unprofessionell.
Wie kann man das besser machen? Na man kann eine Art Binär-sprintf definieren, dem man dann halt die konstanten Fragmente übergibt, und dazwischen die Werte, die man eingetragen haben will. Klingt gut, ist lesbar, aber natürlich total ineffizient. Und man muss, da die konstanten Fragmente Null-Bytes enthalten können, auch jeweils die Länge der Fragmente zählen und übergeben und ist damit so weit wie vorher.
Oder man kann Code schreiben, der jedes Byte (auch die konstanten) manuell in das Zielarray einträgt. Das ist immenser Bloat und total ineffizient.
Ich habe mir also überlegt, hey, an sich kann das doch der Compiler für mich zählen. Ich trage im Template "magische Werte" ein, z.B. "d1__", und rufe dann eine Funktion auf, die das Offsets dieses magischen Wertes raussucht. Compiler können heute konstante Teilausdrücke erkennen. Also, dachte ich mir, drücke ich das Problem mal so aus, dass der Compiler sieht, dass das die Teilausdrücke zur Laufzeit berechenbar sind.
Erster Versuch:
static size_t ofs32(const char* const buf,size_t len,const char* const x) {
size_t i;
for (i=0; i<len-4; ++i)
if (buf[i]==x[0] && buf[i+1]==x[1] && buf[i+2]==x[2] && buf[i+3]==x[3])
return i;
return -1;
}
Dann muss man beim Aufruf natürlich auch das Array, das man als erstes Argument übergibt, als const char whatever[] deklarieren, damit der Compiler weiß, dass das auch sonst keiner manipuliert. Ausprobiert — tut nicht. gcc inlined die Funktion zwar wunschgemäß, aber generiert Code für eine Schleife. Mit -funroll-all-loops rollt er die Schleife aus, erkennt aber immer noch nicht, dass das Ergebnis konstant ist und zur Compilezeit berechnet werden könnte.
Am Ende bin ich dann zu einem Makro ausgewichen, das allerdings echt eklig ist. Ich gebe es hier mal als Auszug wieder:
#define OFS32(buf,x) 
((buf[0]==x[0] && buf[0+1]==x[1] && buf[0+2]==x[2] && buf[0+3]==x[3])?0:
((buf[1]==x[0] && buf[1+1]==x[1] && buf[1+2]==x[2] && buf[1+3]==x[3])?1:
[...]
((buf[31]==x[0] && buf[31+1]==x[1] && buf[31+2]==x[2] && buf[31+3]==x[3])?31:
-1))))))))))))))))))))))))))))))))
Sieht sehr widerlich aus, aber wird vom Compiler korrekt zur Compilezeit ausgewertet und reicht für meine Anwendung. Falls einer von euch weiß, wie man das so deklarieren kann, dass das magenschonender aussieht, aber von gcc doch zur Compilezeit ausgerechnet wird, bitte ich um eine Email.

[zurück] [ältere Posting][neuere Posting]
[zurück] [ältere Posting][neuere Posting]

Fefes Latest Youtube Video Links