2008-12-17 3 views
32

Gibt es eine Möglichkeit, explizite Umwandlung für typedefs des gleichen Typs zu erzwingen? Ich muss mit utf8 umgehen und manchmal werde ich mit den Indizes für die Anzahl der Zeichen und die Anzahl der Bytes verwirrt. So ist es schön, ein paar typedefs haben:Erzwingen Sie die starke Typüberprüfung in C (type strictness für typedefs)

typedef unsigned int char_idx_t; 
typedef unsigned int byte_idx_t; 

Mit dem Zusatz, dass Sie eine explizite Umwandlung zwischen ihnen benötigen:

char_idx_t a = 0; 
byte_idx_t b; 

b = a; // compile warning 
b = (byte_idx_t) a; // ok 

Ich weiß, dass eine solche Funktion nicht in C existiert, aber vielleicht Sie kennen einen Trick oder eine Compiler-Erweiterung (vorzugsweise gcc), die das tut.


EDIT Ich weiß wirklich noch nicht, wie die ungarische Notation im Allgemeinen. Ich konnte es wegen der Codekonventionen für das Projekt nicht für dieses Problem verwenden, aber ich habe es jetzt in einem anderen ähnlichen Fall verwendet, wo auch die Typen die gleichen sind und die Bedeutungen sehr ähnlich sind. Und ich muss zugeben: Es hilft. Ich würde niemals jede ganze Zahl mit einem Anfangs "i" deklarieren, aber wie in Joels Beispiel für überlappende Typen kann es lebensrettend sein.

+2

Es gibt einen anderen sehr schönen Artikel (Obwohl ich nicht einverstanden bin, goto zu verbieten :)) von [Joel] (http://www.joelonsoftware.com/) benannt [Making Wrong Code Look Wrong] (http://www.joelonsoftware.com/articles/Wrong.html). Ich denke, es ist sehr auf deine Frage bezogen, auch wenn es keine direkte Verbindung gibt. – Ilya

+0

Die "interessanteste" und wichtigste Sache in diesem Artikel, IMHO, ist das Stück über die Geschichte der ungarischen Notation. Veeery interessant ... – Noein

Antwort

2

Wenn Sie C++ schreiben, könnten Sie zwei identisch definierte Klassen mit unterschiedlichen Namen erstellen, die Wrapper um einen unsigned int sind. Ich weiß nicht, von einem Trick zu tun, was man in C. wollen

+2

C funktioniert auf die gleiche Weise mit Strukturen. Microsoft verwendet dies, um Handle-Typen in Windows.h zu unterscheiden. –

18

Sie könnte so etwas wie tun:

char_idx a; 
byte_idx b; 

b.b_idx = a.c_idx; 

:

typedef struct { 
    unsigned int c_idx; 
} char_idx; 

typedef struct { 
    unsigned int b_idx; 
} byte_idx; 

Dann würden Sie sehen, wenn Sie jede verwenden Jetzt ist es klarer, dass sie verschiedene Typen sind, aber trotzdem kompilieren würden.

18

für "handle" Typen (opaque Zeiger), verwendet Microsoft den Trick Strukturen deklarieren und dann einen Zeiger auf die Struktur typedef'ing:

#define DECLARE_HANDLE(name) struct name##__ { int unused; }; \ 
          typedef struct name##__ *name 

Dann statt

typedef void* FOOHANDLE; 
typedef void* BARHANDLE; 

Sie tun:

DECLARE_HANDLE(FOOHANDLE); 
DECLARE_HANDLE(BARHANDLE); 

So, jetzt, das funktioniert:

FOOHANDLE make_foo(); 
BARHANDLE make_bar(); 
void do_bar(BARHANDLE); 

FOOHANDLE foo = make_foo(); /* ok */ 
BARHANDLE bar = foo;   /* won't work! */ 
do_bar(foo);     /* won't work! */ 
7

Verwenden Sie eine Flusen. Siehe Splint:Types und strong type check.

Starke Typprüfung zeigt oft Programmierfehler. Splint kann primitive C-Typen strenger und flexibel als typische Compiler (4.1) überprüfen und bietet einen booleschen Typ (4.2). Darüber hinaus können Benutzer abstrakte Typen definieren, die Informationen verbergen (0) bereitstellen.

4

In C ist die einzige Unterscheidung zwischen benutzerdefinierte Typendie vom Compiler erzwungen wird, ist die Unterscheidung zwischen structs. Jeder typedef mit verschiedenen Strukturen funktioniert. Ihre Hauptdesignfrage ist sollten verschiedene Strukturtypen die gleichen Mitgliedsnamen verwenden? Wenn ja, können Sie polymorphen Code mit Makros und anderen Skorbut-Tricks simulieren. Wenn nicht, sind Sie wirklich zwei verschiedenen Darstellungen verpflichtet. Zum Beispiel, möchten Sie

#define INCREMENT(s, k) ((s).n += (k)) 

und INCREMENT sowohl byte_idx und char_idx nutzen können wollen? Dann benennen Sie die Felder identisch.

3

Sie haben nach Erweiterungen gefragt. Jeff Foster's CQual ist sehr nett, und ich denke, es könnte die Arbeit tun, die Sie wollen.

+0

Gibt es ähnliche Programme, die noch aktiv sind (die letzte Aktualisierung der Webseite von CQual war 2004) – CodeMonkey

14

Was Sie wollen, heißt "strong typedef" oder "strict typedef".

Einige Programmiersprachen [Rust, D, Haskell, Ada, ...] unterstützen dies auf Sprachniveau, C [++] nicht. Es gab einen Vorschlag, es in die Sprache mit dem Namen "opaque typedef" aufzunehmen, wurde aber nicht akzeptiert.

Der Mangel an Sprachunterstützung ist jedoch kein Problem. Umbrechen Sie einfach den zu aliasierenden Typ in eine neue Klasse mit genau einem Datenelement vom Typ T. Ein Großteil der Wiederholung kann durch Vorlagen und Makros ausgeklammert werden. Diese einfache Technik ist genauso praktisch wie in den Programmiersprachen mit direkter Unterstützung.

1

Mit C 11 ++ Sie eine ENUM-Klasse verwenden können, beispielsweise

enum class char_idx_t : unsigned int {}; 
enum class byte_idx_t : unsigned int {}; 

Der Compiler wird eine explizite Umwandlung zwischen den beiden Typen erzwingen; Es ist wie eine dünne Wrapper-Klasse. Leider haben Sie keine Bedienerüberlastung, z. Wenn Sie zwei char_idx_t zusammenfügen möchten, müssen Sie sie in unsigned int umwandeln.

+0

Siehe Vorschlag Revision (3) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf – qub1n

Verwandte Themen