Was ist Ihr Lieblings-C-Programmiertrick? [closed]

Lesezeit: 6 Minuten

Zum Beispiel bin ich kürzlich im Linux-Kernel auf Folgendes gestoßen:

/* Force a compilation error if condition is true */
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

Wenn Sie also in Ihrem Code eine Struktur haben, die beispielsweise ein Vielfaches von 8 Bytes groß sein muss, möglicherweise aufgrund einiger Hardwareeinschränkungen, können Sie Folgendes tun:

BUILD_BUG_ON((sizeof(struct mystruct) % 8) != 0);

und es wird nicht kompiliert, es sei denn, die Größe von struct mystruct ist ein Vielfaches von 8, und wenn es ein Vielfaches von 8 ist, wird überhaupt kein Laufzeitcode generiert.

Ein weiterer Trick, den ich kenne, stammt aus dem Buch “Graphics Gems”, der es einer einzelnen Header-Datei ermöglicht, Variablen in einem Modul sowohl zu deklarieren als auch zu initialisieren, während sie in anderen Modulen, die dieses Modul verwenden, lediglich als extern deklariert werden.

#ifdef DEFINE_MYHEADER_GLOBALS
#define GLOBAL
#define INIT(x, y) (x) = (y)
#else
#define GLOBAL extern
#define INIT(x, y)
#endif

GLOBAL int INIT(x, 0);
GLOBAL int somefunc(int a, int b);

Damit macht der Code, der x und somefunc definiert:

#define DEFINE_MYHEADER_GLOBALS
#include "the_above_header_file.h"

während Code, der nur x und somefunc() verwendet, Folgendes tut:

#include "the_above_header_file.h"

Sie erhalten also eine Header-Datei, die sowohl Instanzen von Globals als auch Funktionsprototypen dort deklariert, wo sie benötigt werden, sowie die entsprechenden externen Deklarationen.

Also, was sind Ihre liebsten C-Programmiertricks in dieser Richtung?

  • Dies scheint eher ein C-Präprozessor-Trick zu sein.

    – Jmucchiello

    1. März 2009 um 10:24 Uhr

  • Um BUILD_BUG_ON Makro, was ist falsch an der Verwendung #error innen und #if?

    – Ricardo

    15. Oktober 2011 um 11:46 Uhr

Beim Lesen des Quellcodes von Quake 2 kam ich auf etwas wie das Folgende:

double normals[][] = {
  #include "normals.txt"
};

(Mehr oder weniger habe ich den Code nicht zur Hand, um ihn jetzt zu überprüfen).

Seitdem hat sich vor meinen Augen eine neue Welt der kreativen Nutzung des Präprozessors geöffnet. Ich füge nicht mehr nur Header ein, sondern hin und wieder ganze Code-Blöcke (es verbessert die Wiederverwendbarkeit erheblich) :-p

Danke John Carmack! xD

  • Sie können in einem Optimierungsthread nicht Carmack sagen, ohne den schnellen inversen Quadrat zu erwähnen, der in der Bebenquelle enthalten war. en.wikipedia.org/wiki/Fast_inverse_square_root

    – Seite 1989

    14. Oktober 2011 um 14:56 Uhr

  • Woher hat er überhaupt 0x5f3759df?

    – Rory Harvey

    14. Oktober 2011 um 16:23 Uhr

  • @RoryHarvey: Nach dem, was ich beim Nachschlagen finden konnte, scheint es rein empirisch zu sein. Einige Studien (ich weiß nicht mehr, wo ich sie gesehen habe) zeigten, dass es nahezu optimal, aber nicht vollständig optimal war. Ebenso scheint es, dass für 64 Bit der Wert entdeckt wurde, anstatt zu berechnen.

    – Matthias M.

    14. Oktober 2011 um 16:28 Uhr

  • Für globale Variablen übrigens nicht erforderlich.

    – Nachzügler

    1. März 2009 um 20:41 Uhr

  • Nicht benötigt für statisch Variablen. Globale Variablen können auf Null gesetzt werden, dies ist jedoch nicht erforderlich.

    – Jamie

    23. Oktober 2009 um 13:23 Uhr

  • Ich erweitere dies manchmal auf: const struct something zero_something = { 0 }; und dann kann ich eine Variable spontan mit zurücksetzen struct something X = zero_something; oder auf halbem Weg durch eine Routine kann ich ‘X = zero_something;’ verwenden. Der einzige mögliche Einwand ist, dass es darum geht, Daten von irgendwoher zu lesen; Heutzutage ist ein ‘memset()’ vielleicht schneller – aber ich mag die Klarheit der Zuweisung, und es ist auch möglich, andere Werte als Null im Initialisierer zu verwenden (und memset(), gefolgt von Anpassungen an einzelne Mitglieder möglicherweise langsamer als eine einfache Kopie).

    – Jonathan Leffler

    2. November 2009 um 15:55 Uhr

Wenn wir über C-Tricks sprechen, muss mein Favorit sein Duffs Gerät zum Schlaufenabrollen! Ich warte nur auf die richtige Gelegenheit, damit ich sie tatsächlich im Zorn ausnutzen kann …

  • Ich habe es einmal verwendet, um einen messbaren Leistungsgewinn zu erzielen, aber heutzutage ist es für viele Hardware nicht mehr nützlich. Immer profilieren!

    – Dan Olson

    1. März 2009 um 8:12 Uhr

  • Ja, die Art von Leuten, die den Kontext nicht verstehen, in dem Duffs Gerät erstellt wurde: “Code-Lesbarkeit” ist nutzlos, wenn der Code nicht schnell genug ist, um zu funktionieren. Wahrscheinlich musste keiner der Leute, die Sie herabgestimmt haben, jemals für harte Echtzeit programmieren.

    – Rob K

    3. März 2009 um 18:09 Uhr

  • +1, ich musste tatsächlich ein paar Mal Duffs Gerät benutzen. Das erste Mal war ein Loop, der im Grunde nur Sachen kopierte und dabei ein paar kleine Transformationen durchführte. Es war viel, viel schneller als ein einfaches memcpy() in dieser Architektur.

    – Makis

    30. Juni 2009 um 9:24 Uhr

  • Der Ärger kommt von Ihren Kollegen und Nachfolgern, die Ihren Code nach Ihnen pflegen müssen.

    – Jonathan Leffler

    2. November 2009 um 15:50 Uhr

  • Wie gesagt, ich warte noch auf die richtige Gelegenheit – aber genervt hat mich noch keiner genug. Ich schreibe jetzt seit ungefähr 25 Jahren C, ich glaube, ich bin Anfang der 90er Jahre zum ersten Mal auf Duffs Gerät gestoßen und musste es noch nicht verwenden. Wie andere kommentiert haben, ist diese Art von Trick jetzt immer weniger nützlich, da Compiler bei dieser Art der Optimierung besser werden.

    – Jackson

    2. November 2009 um 16:58 Uhr

verwenden __FILE__ und __LINE__ zum Debuggen

#define WHERE fprintf(stderr,"[LOG]%s:%d\n",__FILE__,__LINE__);

  • Ich habe es einmal verwendet, um einen messbaren Leistungsgewinn zu erzielen, aber heutzutage ist es für viele Hardware nicht mehr nützlich. Immer profilieren!

    – Dan Olson

    1. März 2009 um 8:12 Uhr

  • Ja, die Art von Leuten, die den Kontext nicht verstehen, in dem Duffs Gerät erstellt wurde: “Code-Lesbarkeit” ist nutzlos, wenn der Code nicht schnell genug ist, um zu funktionieren. Wahrscheinlich musste keiner der Leute, die Sie herabgestimmt haben, jemals für harte Echtzeit programmieren.

    – Rob K

    3. März 2009 um 18:09 Uhr

  • +1, ich musste tatsächlich ein paar Mal Duffs Gerät benutzen. Das erste Mal war ein Loop, der im Grunde nur Sachen kopierte und dabei ein paar kleine Transformationen durchführte. Es war viel, viel schneller als ein einfaches memcpy() in dieser Architektur.

    – Makis

    30. Juni 2009 um 9:24 Uhr

  • Der Ärger kommt von Ihren Kollegen und Nachfolgern, die Ihren Code nach Ihnen pflegen müssen.

    – Jonathan Leffler

    2. November 2009 um 15:50 Uhr

  • Wie gesagt, ich warte noch auf die richtige Gelegenheit – aber genervt hat mich noch keiner genug. Ich schreibe jetzt seit ungefähr 25 Jahren C, ich glaube, ich bin Anfang der 90er Jahre zum ersten Mal auf Duffs Gerät gestoßen und musste es noch nicht verwenden. Wie andere kommentiert haben, ist diese Art von Trick jetzt immer weniger nützlich, da Compiler bei dieser Art der Optimierung besser werden.

    – Jackson

    2. November 2009 um 16:58 Uhr

Im C99

typedef struct{
    int value;
    int otherValue;
} s;

s test = {.value = 15, .otherValue = 16};

/* or */
int a[100] = {1,2,[50]=3,4,5,[23]=6,7};

1423520cookie-checkWas ist Ihr Lieblings-C-Programmiertrick? [closed]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy