Ich bin also weit davon entfernt, ein C-Experte zu sein, aber etwas stört mich an Code, den ich schon lange lese: Kann mir jemand erklären, warum C(++)-Programmierer Typedefs verwenden, um einfache Typen umzubenennen? Ich verstehe, warum Sie sie für Strukturen verwenden würden, aber was genau ist der Grund für Deklarationen, die ich sehe
typedef unsigned char uch;
typedef uch UBYTE;
typedef unsigned long ulg;
typedef unsigned int u32;
typedef signed short s16;
Gibt es einen Vorteil, der mir nicht klar ist (ein Programmierer, dessen Erfahrung mit Java beginnt und der sich nicht weit über streng typsichere Sprachen hinaus gewagt hat)? Weil ich mir keinen Grund dafür vorstellen kann – es sieht so aus, als würde es den Code für Leute, die mit dem Projekt nicht vertraut sind, weniger lesbar machen.
Fühlen Sie sich frei, mich wie einen C-Neuling zu behandeln, ich weiß ehrlich gesagt sehr wenig darüber und es ist wahrscheinlich, dass es Dinge gibt, die ich von Anfang an falsch verstanden habe. 😉
Das Umbenennen von Typen, ohne ihre exponierte Semantik/Eigenschaften zu ändern, macht nicht viel Sinn. In deinem Beispiel
typedef unsigned char uch;
typedef unsigned long ulg;
gehören zu dieser Kategorie. Ich sehe keinen Sinn, abgesehen davon, einen kürzeren Namen zu machen.
Aber diese
typedef uch UBYTE;
typedef unsigned int u32;
typedef signed short s16;
sind eine ganz andere Geschichte. Zum Beispiel, s16
steht für “signed 16 bit type”. Diese Art ist nicht unbedingt signed short
. Welcher spezifische Typ wird sich dahinter verstecken s16
ist plattformabhängig. Programmierer führen diese zusätzliche Ebene der Namensumleitung ein, um die Unterstützung für mehrere Plattformen zu vereinfachen. Wenn auf einer anderen Plattform ein signierter 16-Bit-Typ vorliegt signed int
muss der Programmierer nur eine typedef-Definition ändern. UBYTE
steht anscheinend für einen vorzeichenlosen Maschinenbytetyp, was nicht unbedingt der Fall ist unsigned char
.
Es ist erwähnenswert, dass die C99-Spezifikation bereits eine Standardnomenklatur für integrale Typen mit bestimmter Breite bereitstellt, wie z int16_t
, uint32_t
usw. Auf Plattformen, die C99 nicht unterstützen, ist es wahrscheinlich sinnvoller, sich an diese Standard-Namenskonvention zu halten.
Dies ermöglicht eine Portabilität. Beispielsweise benötigen Sie einen vorzeichenlosen 32-Bit-Ganzzahltyp. Welcher Standardtyp ist das? Sie wissen es nicht – es ist die Implementierung definiert. Deshalb du typedef
einen separaten Typ als 32-Bit-Ganzzahl ohne Vorzeichen und verwenden Sie den neuen Typ in Ihrem Code. Wenn Sie auf einer anderen C-Implementierung kompilieren müssen, ändern Sie einfach die typedef
s.
Manchmal wird es verwendet, um eine unhandliche Sache wie zu reduzieren volatile unsigned long
etwas Kompakteres wie z vuint32_t
.
In anderen Fällen soll es bei der Portabilität helfen, da Typen wie int
sind nicht immer auf jeder Plattform gleich. Durch die Verwendung einer Typedef können Sie die Speicherklasse, an der Sie interessiert sind, auf die beste Übereinstimmung der Plattform setzen, ohne den gesamten Quellcode zu ändern.
Es gibt viele Gründe dafür. Was ich denke ist:
- Typename wird kürzer und damit auch Code kleiner und besser lesbar.
- Aliasing-Effekt für längere Strukturnamen.
- Konvention, die in bestimmten Teams / Unternehmen / Stilen verwendet wird.
- Portierung – Haben denselben Namen für alle Betriebssysteme und Maschinen. Die native Datenstruktur kann etwas anders sein.
Es folgt ein Zitat aus The C Programming Language (K&R)
Neben rein ästhetischen Aspekten gibt es zwei Hauptgründe für die Verwendung von Typedefs.
Erstens, um ein Programm zu parametrisieren
Die erste besteht darin, ein Programm gegen Portabilitätsprobleme zu parametrisieren. Wenn Typedefs für Datentypen verwendet werden, die möglicherweise maschinenabhängig sind, müssen nur die Typedefs geändert werden, wenn das Programm verschoben wird.
Eine übliche Situation besteht darin, typedef-Namen für verschiedene ganzzahlige Mengen zu verwenden und dann für jeden Hostcomputer eine geeignete Auswahl von short, int und long zu treffen. Beispiele sind Typen wie size_t und ptrdiff_t aus der Standardbibliothek.
Die kursiv gedruckten Teile sagen uns, dass Programmierer typedef
Grundtyp für Portabilität. Wenn ich sicherstellen möchte, dass mein Programm auf verschiedenen Plattformen funktioniert und verschiedene Compiler verwende, werde ich versuchen, sicherzustellen, dass seine Portabilität auf jede erdenkliche Weise und typedef
Ist einer von ihnen.
Als ich anfing, mit dem Turbo C-Compiler auf der Windows-Plattform zu programmieren, bekamen wir die Größe von int
2. Als ich zur Linux-Plattform und zum GCC-Compiler wechselte, erhalte ich eine Größe von 4. Wenn ich ein Programm mit Turbo C entwickelt hätte, das sich auf die Behauptung stützte, dass sizeof( int )
ist immer zwei, hätte es nicht richtig auf meine neue Plattform portiert.
Ich hoffe es hilft.
Das folgende Zitat von K&R bezieht sich nicht auf Ihre Anfrage, aber ich habe es der Vollständigkeit halber ebenfalls gepostet.
Zweitens, um eine bessere Dokumentation bereitzustellen
Der zweite Zweck von typedefs besteht darin, eine bessere Dokumentation für ein Programm bereitzustellen – ein Typ namens Treeptr ist möglicherweise leichter zu verstehen als einer, der nur als Zeiger auf eine komplizierte Struktur deklariert ist.
Die meisten dieser Muster sind schlechte Praktiken, die durch das Lesen und Kopieren von vorhandenem fehlerhaftem Code entstehen. Oft spiegeln sie Missverständnisse darüber wider, was C tut oder nicht erfordert.
- Ist ähnlich
#define BEGIN {
außer es spart etwas Tipparbeit, anstatt mehr zu machen.
- Ist ähnlich
#define FALSE 0
. Wenn Ihre Vorstellung von “Byte” die kleinste adressierbare Einheit ist, char
ist per Definition ein Byte. Wenn Ihre Vorstellung von “Byte” ein Oktett ist, dann entweder char
der Oktetttyp ist, oder Ihre Maschine hat keinen Oktetttyp.
- Ist wirklich hässliche Abkürzung für Leute, die nicht tippen können …
- Ist ein Fehler. Es sollte sein
typedef uint32_t u32;
oder noch besser, uint32_t
sollte nur direkt verwendet werden.
- Ist dasselbe wie 4. Ersetzen
uint32_t
mit int16_t
.
Bitte setzen Sie ein “als schädlich angesehen„Stempel auf sie alle. typedef
sollte verwendet werden, wenn Sie wirklich einen neuen Typ erstellen müssen, dessen Definition sich im Laufe des Lebenszyklus Ihres Codes ändern könnte, oder wenn der Code auf andere Hardware portiert wird, nicht weil Sie denken, dass C mit anderen Typnamen “schöner” wäre.
Wir verwenden es, um es projekt-/plattformspezifisch zu machen, alles hat eine gemeinsame Namenskonvention
pname_int32, pname_uint32, pname_uint8
— pname ist Projekt-/Plattform-/Modulname
Und einige #definiert
pname_malloc, pname_strlen
Es ist einfacher zu lesen und verkürzt lange Datentypen wie unsigned char auf pname_uint8 und macht es auch zu einer Konvention für alle Module.
Beim Portieren müssen Sie nur die einzelne Datei ändern, was das Portieren vereinfacht.
14119600cookie-checkWarum verwenden C-Programmierer Typedefs, um grundlegende Typen umzubenennen?yes
Sollte man sich anschauen
stdint.h
. Sie werden auch verwendet, wenn sich der Typ von etwas vom System unterscheiden kann, der Code jedoch kompatibel bleiben muss.– Nategans
27. Juli 2010 um 20:39 Uhr