Seite 1 von 3

Casten mit Carsten

Verfasst: Mi Jul 23, 2008 12:10 pm
von AnGaiNoR
Unter der Prioritätentabelle steht, dass Casten ein Zeichen schlechten Programmierstils ist.
Meiner Meinung nach kommt man manchmal ohne Ca(r)sten gar nicht aus.

Beispiel: Die (Windows-)Funktion zum auslesen eines Registry-Wertes

Code: Alles auswählen

WINADVAPI
LONG
APIENTRY
RegQueryValueExA (
    __in HKEY hKey,
    __in_opt LPCSTR lpValueName,
    __reserved LPDWORD lpReserved,
    __out_opt LPDWORD lpType,
    __out_bcount_opt(*lpcbData) LPBYTE lpData,
    __inout_opt LPDWORD lpcbData
    );
Das Argument lpData ist immer ein Zeiger auf ein BYTE-Array.
Wenn ich aber eine Zeichenkette auslesen will, dann muss ich einen TypeCast (reinterpret_cast) verwenden.

Re: Type-Casts

Verfasst: Mi Jul 23, 2008 12:25 pm
von Kerli
AnGaiNoR hat geschrieben:Unter der Prioritätentabelle steht, dass Casten ein Zeichen schlechten Programmierstils ist.
Meiner Meinung nach kommt man manchmal ohne Ca(r)sten gar nicht aus.

Beispiel: Die (Windows-)Funktion zum auslesen eines Registry-Wertes

Code: Alles auswählen

WINADVAPI
LONG
APIENTRY
RegQueryValueExA (
    __in HKEY hKey,
    __in_opt LPCSTR lpValueName,
    __reserved LPDWORD lpReserved,
    __out_opt LPDWORD lpType,
    __out_bcount_opt(*lpcbData) LPBYTE lpData,
    __inout_opt LPDWORD lpcbData
    );
Das Argument lpData ist immer ein Zeiger auf ein BYTE-Array.
Wenn ich aber eine Zeichenkette auslesen will, dann muss ich einen TypeCast (reinterpret_cast) verwenden.
Wer sagt denn, dass die WinAPI gut programmiert ist :D
Nein Spaß beiseite. Es gibt natürlich auch Fälle in denen es durchaus angebracht ist casts zu verwenden, wenn man allerdings zu häufig davon Gebrauch machen muss, dann hat man wahrscheinlich irgendwo einen Designfehler drinnen.

Re: Type-Casts

Verfasst: Mi Jul 23, 2008 1:30 pm
von Xin
AnGaiNoR hat geschrieben:Unter der Prioritätentabelle steht, dass Casten ein Zeichen schlechten Programmierstils ist.
Meiner Meinung nach kommt man manchmal ohne Ca(r)sten gar nicht aus.

Beispiel: Die (Windows-)Funktion zum auslesen eines Registry-Wertes
Aber das ist doch kein Widerspruch?

Wenn es ein allgemein anerkanntes Beispiel für total verkorkstes Softwaredesign gibt, dann steht die WinAPI definitiv in den Top10 und dort besetzt sie alle 10 Plätze mit großem Abstand zum nächst schlechtesten Design.

Carsten kann programmieren, der braucht nicht zu casten.

Re: C:Ausdrücke

Verfasst: Mi Jul 23, 2008 1:31 pm
von Dirty Oerti
Ich finde Casten an sich eigentlich eine sehr gute Möglichkeit...
Und für schlechten Programmierstil halte ich es erst recht nicht.

Manchmal geht's sogar nicht ohne... da braucht man dann einen Cast.

Re: C:Ausdrücke

Verfasst: Mi Jul 23, 2008 1:34 pm
von Xin
Dirty Oerti hat geschrieben:Ich finde Casten an sich eigentlich eine sehr gute Möglichkeit...
Und für schlechten Programmierstil halte ich es erst recht nicht.
Gute Möglichkeit für was?
Dirty Oerti hat geschrieben:Manchmal geht's sogar nicht ohne... da braucht man dann einen Cast.
Es geht immer ohne Cast.

Re: C:Ausdrücke

Verfasst: Mi Jul 23, 2008 1:45 pm
von AnGaiNoR
Xin hat geschrieben:Es geht immer ohne Cast.
Na dann bräuchtest du für meine EINE Beispielfunktion aber 6.

Re: C:Ausdrücke

Verfasst: Mi Jul 23, 2008 1:53 pm
von Xin
AnGaiNoR hat geschrieben:
Xin hat geschrieben:Es geht immer ohne Cast.
Na dann bräuchtest du für meine EINE Beispielfunktion aber 6.
Nein, Du brauchst einen Entwickler, der sich auf's Wesentliche konzentrieren kann.

Re: Ausdrücke in C

Verfasst: Mi Jul 23, 2008 4:34 pm
von fat-lobyte
Kerli hat geschrieben:
AnGaiNoR hat geschrieben:Meinst du mit "Ausdrücke" etwa "Regular Expressions"?
Damit hab ich mich leider noch nicht beschäftigt, aber wenn ihr es schafft mich dazu anzuregen... ^^
Nein mit Ausdrücken ist da etwas anderes gemeint - In C/C++ verwendet man 'regular expressions' nicht so oft, weil es keine solchen Funktionen in der Standardbibliothek gibt.
NOCH gibt es die nicht. Ab ca. 2009 gibts dann nen neuen Standard, wo es dann hochoffiziell Regular Expressions gibt. Manche Compiler haben die Libs bereits, und zwar im namespace std::tr1.

Zum Thema Casten:
Manchmal geht es einfach nicht ohne. Beispiel Nr. 1:

Code: Alles auswählen

#include <stdlib.h>

...
int* integer_array = (int*) malloc(ARRAYSIZE*sizeof(int));
Beispiel Nr. 2:

Code: Alles auswählen

/* Ich will einfach nur einen Puffer von bytes haben,
* zum beispiel um Netzwerkpakete zusammenzubauen
*/
unsigned char buffer[BUFSIZE];

*(unsigned int*) buffer = packet_length;
*((unsigned short) (buffer+sizeof(unsigned int)) = header_length;
...
Beispiel Nr 3, jetzt aus C++:

Code: Alles auswählen

struct Base 
{
    bool is_A;

    virtual void boringFunction() = 0;

    Base(bool _is_A)
        : is_A(_is_A)
    {}

};

struct DerivedA 
{
    DerivedA()
        : Base(true)
    {}

    virtual void boringFunction()
    {}

    void wickedFunction()
    {}
}

struct DerivedB 
{
    DerivedB()
        : Base(false)
    {}

    virtual void boringFunction()
    {}

    void coolFunction()
    {}
}

void handler(Base* base)
{
    if (base->is_A)
    {
        dynamic_cast<DerivedA>(base)->wickedFunction();
    }
    else 
    {
        dynamic_cast<DerivedA>(base)->coolFunction();
    }
}

Re: Ausdrücke in C

Verfasst: Mi Jul 23, 2008 6:49 pm
von Xin
fat-lobyte hat geschrieben:Zum Thema Casten:
Manchmal geht es einfach nicht ohne. Beispiel Nr. 1:

Code: Alles auswählen

#include <stdlib.h>
...
int* integer_array = (int*) malloc(ARRAYSIZE*sizeof(int));
Wozu gibt es in C++ new?

Ansonsten:

Code: Alles auswählen

union IntegerPointer
{
  void * MemoryHandling;
  int * IntegerArray;
};

union IntegerPointer intP;

intP.MemoryHandling = malloc( ARRAYSIZE * sizeof( int ) );
intP.IntegerArray[0] = 1;
Mit dem Cast darf man integer_array auch mal nach (char *) konvertieren und auf einen String zeigen lassen. union IntegerPointer lässt das nicht zu.
fat-lobyte hat geschrieben:Beispiel Nr. 2:

Code: Alles auswählen

/* Ich will einfach nur einen Puffer von bytes haben,
* zum beispiel um Netzwerkpakete zusammenzubauen
*/
unsigned char buffer[BUFSIZE];

*(unsigned int*) buffer = packet_length;
*((unsigned short) (buffer+sizeof(unsigned int)) = header_length;
...
C++ Lösung: Klasse erstellen, bestehend aus eigenen Longs, die sich als char-Array zurückgeben lassen.
C Lösung: Funktionen verwenden, die klare Aussagen treffen, was sie tun. Hier könnte man sich wieder mit Unions behelfen, aber hier würde ich Casting akzeptieren, wenn es nur in den passenden Funktionen stattfinden würde.

Code: Alles auswählen

WriteUnsignedint( char ** buffer, unsigned int l )
{
  *((unsigned int *) *buffer) = l;
  *buffer += sizeof( long );
}
WriteUnsignedShort( char ** buffer, unsigned short s )
{
  *((unsigned int *) *buffer) = s;
  *buffer += sizeof( short );
}
...
unsigned char buffer[BUFSIZE];
unsigned char ** bufferPos = &buffer;

WriteUnsignedLong( bufferPos, packed_length );
WriteUnsignedShort( bufferPos, header_length );
fat-lobyte hat geschrieben: Beispiel Nr 3, jetzt aus C++:

Code: Alles auswählen

struct Base 
{
    bool is_A;

    virtual void boringFunction() = 0;

    Base(bool _is_A)
        : is_A(_is_A)
    {}

};

struct DerivedA 
{
    DerivedA()
        : Base(true)
    {}

    virtual void boringFunction()
    {}

    void wickedFunction()
    {}
}

struct DerivedB 
{
    DerivedB()
        : Base(false)
    {}

    virtual void boringFunction()
    {}

    void coolFunction()
    {}
}

void handler(Base* base)
{
    if (base->is_A)
    {
        dynamic_cast<DerivedA>(base)->wickedFunction();
    }
    else 
    {
        dynamic_cast<DerivedA>(base)->coolFunction();
    }
}
Grober Designfehler...

Code: Alles auswählen

struct Base 
{
    bool is_A;

    virtual void boringFunction() = 0;

    Base(bool _is_A)
        : is_A(_is_A)
    {}

    virtual void handler() = 0;
};

struct DerivedA : public Base // <- gehe ich mal von aus...
{
    DerivedA()
        : Base(true)
    {}

    virtual void boringFunction()
    {}

    void wickedFunction()
    {}

    void handler()
    {
      wickedFunction();
    }
}

struct DerivedB : public Base
{
    DerivedB()
        : Base(false)
    {}

    virtual void boringFunction()
    {}

    void coolFunction()
    {}

    void handler()
    {
      coolFunction();
    }

}
Casten ist immer nur ein Armutszeugnis für einen Entwickler. In Beispiel 2 ist casten eine Vereinfachung, Lösung 1 würde hier auch greifen. Lösung 1 ist im letztendlich das gleiche wie Casten, aber es ist vorher klar, dass man nicht überall hinkonvertieren kann, sondern nur zu festgelegte Typen.
Casten in C++ ist ein Zeichen ist so gut wie überhaupt nicht mehr notwendig. Es gibt Fälle mit Templates, da komme ich nicht um Casten rum, um Redundanz zu vermeiden. Bevor ein Cast verwendet wird, sollte man lieber mal ein paar Tage in sich gehen und überlegen, was es für Alternativen gibt.

Re: Ausdrücke in C

Verfasst: Mi Jul 23, 2008 7:11 pm
von Dirty Oerti
Xin hat geschrieben:
fat-lobyte hat geschrieben:Zum Thema Casten:
Manchmal geht es einfach nicht ohne. Beispiel Nr. 1:

Code: Alles auswählen

#include <stdlib.h>
...
int* integer_array = (int*) malloc(ARRAYSIZE*sizeof(int));
Wozu gibt es in C++ new?
Was ist aber, wenn du C schreiben MUSST ?