Post by Stefan ReutherPost by Rainer WeikusatAllerdings mag ich die "Mikro-Pessimierungen", was ich als "misslungener
Versuch, durch seltsame C-Konstruktionen Takte zu schinden" nicht auf
mir sitzen zu lassen. Darum geht es mir naemlich grundsaetzlich
nicht. Ich moechte eine in C sinnvolle Formulierung eines Algorithmus
haben und um Uebersetzung in sinnvollen Machinencode soll sich bitte der
Compiler kuemmern.
Das wichtigste Optimierungsziel sollte eigentlich Lesbarkeit sein, nicht
Anzahl Maschinenbefehle. Schon die Korrelation zwischen Anzahl
Maschinenbefehle und Ausführungszeit ist heute deutlich schwächer als
vor 20 Jahren, aber spätestens bei der Lesbarkeit wird's vollends
unvorhersehbar^Wsubjektiv.
Da würde ich der Formulierung, so wie sie dasteht, schon ein paar Punkte
Abzug geben. Sicherlich auch aufgrund von Unvertrautheit mit der Codebasis.
Wenn der ternäre Ausdruck aus einem Makro kommt und somit einen Namen hat
#define ANCHOR_NODE(p, c) *(p ? &p->p_me : &c)
ANCHOR_NODE(n_pkg, chain) = pkg->p_me;
Wenn schon, dann etwas in der Art von
-----
#include <stdio.h>
#define DST_IF(cond, d0, d1) *((cond) ? &(d0) : &(d1))
static int a = 3, b = 4;
int main(int argc, char **argv)
{
DST_IF(argv[1], a, b) += 5;
printf("a %d, b %d\n", a, b);
return 0;
}
------
Da sind wenigstens nicht auch noch die Parameternamen unsichtbar drin
versteckt. Allerdings ist man meiner Ansicht nach gut beraten wenn man
von Makros groesstenteils die Finger laesst: Ich empfinde solche
zusaetzlichen Syntaxkonstrukte als extrem leseflussstoerend.
Ein Unterprogram ist ein strukturiertes Konstrukt. Es hat einen
Eintrittspunkt und einen Austrittspunkt und seine Bedeutung ist
unabhaengig vom syntaktischen Kontext des Aufrufs. Ein Makro nimmt
irgendeine Textersetzung vor und man muss die Definition kennen, um die
effektive Bedeutung in einer bestimmten Umgebung vorhersagen zu
koennen.
Abschreckendes Beispiel:
[***@duesterwald]~/work/linux-2-6 $grep '^#define' include/linux/list.h | grep each
#define list_for_each(pos, head) \
#define list_for_each_prev(pos, head) \
#define list_for_each_safe(pos, n, head) \
#define list_for_each_prev_safe(pos, n, head) \
#define list_for_each_entry(pos, head, member) \
#define list_for_each_entry_reverse(pos, head, member) \
#define list_for_each_entry_continue(pos, head, member) \
#define list_for_each_entry_continue_reverse(pos, head, member) \
#define list_for_each_entry_from(pos, head, member) \
#define list_for_each_entry_safe(pos, n, head, member) \
#define list_for_each_entry_safe_continue(pos, n, head, member) \
#define list_for_each_entry_safe_from(pos, n, head, member) \
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
#define hlist_for_each(pos, head) \
#define hlist_for_each_safe(pos, n, head) \
#define hlist_for_each_entry(pos, head, member) \
#define hlist_for_each_entry_continue(pos, member) \
#define hlist_for_each_entry_from(pos, member) \
#define hlist_for_each_entry_safe(pos, n, head, member) \
Das sind 19 unterschiedliche Konfiguration von for (;;;)-Schleifen, die
unterschiedliche, undokumentierte Annahmen ueber ihre Umgebung
enthalten. Kuerzlich musste ich hier ein Basiskernelupdate von 3.2.54
auf 3.16.48 machen. Auf dem Weg dorthin hat jemand aus einem von diesen
Unkraeutern ein Feature ausgebaut, von dem er sich gerade gar nicht
vorstellen konnte, wofuer es gut sein koennte. Leider war das aber eins,
dass ich fuer etwas benutzt hatte. Es hat dann auch nur zwei Tage
Debugging von Oopses gebraucht, bis es mir gelungen war, experimentell
zu ermitteln, wie man das, was der fragliche Code tun muss, unter den
veraenderten Rahmenbedingen so implementiert, dass alles huebsch nett
aussieht (und wieder genauso funktioniert, wie es das seit Jahren
bereits tat).
Post by Stefan Reutheroder wenn das ganze C++ wäre, wo man WIMRE das *& weglassen kann
(n_pkg ? n_pkg->p_me : chain) = pkg->p_me;
wird's zumindest subjektiv ein wenig lesbarer.
C unterstuetzt nunmal keine transparenten Referenzen, bloss Zeigerwerte.