Frage zu Datentyp Konvertierung



  • Hallo, ich wollte gerade einen Quelltext von mir mit einem anderen Compiler übersetzten aber da gab es einen Fehler bei der Datentyp Konvertierung.

    Funktion:

    http://msdn.microsoft.com/en-us/library/windows/desktop/ms724844(v=vs.85).aspx
    
    LONG WINAPI RegCreateKeyEx(
      _In_        HKEY hKey,
      _In_        LPCTSTR lpSubKey,
      _Reserved_  DWORD Reserved,
      _In_opt_    LPTSTR lpClass,
      _In_        DWORD dwOptions,
      _In_        REGSAM samDesired,
      _In_opt_    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
      _Out_       PHKEY phkResult,
      _Out_opt_   LPDWORD lpdwDisposition
    );
    

    Bei meinem Codegear Compiler führe ich die Funktion so aus:

    LPCTSTR ValueName = "TestKey";
    	const BYTE *KeyData = "test";
    	RegSetValueEx(phkResult,ValueName,0,REG_SZ,KeyData, strlen(KeyData)+1);
    

    Bei Codeblocks muss ich es aber so machen:

    LPCTSTR ValueName = "TestKey";
    char *KeyData = "test";
    RegSetValueEx(phkResult,ValueName,0,REG_SZ, (BYTE*)&KeyData, strlen(KeyData)+1);
    

    Weiß jemand was der Compiler hier macht? (BYTE*)&KeyData
    Ich denke mal er übergibt die Adresse der Variable KeyData an die Funktion RegSetValueEx. Aber wenn dem so wäre/ist dann müsste ich doch auch schreiben können:

    LPCTSTR ValueName = "TestKey";
    char *KeyData = "test";
    RegSetValueEx(phkResult,ValueName,0,REG_SZ,&KeyData, strlen(KeyData)+1);
    

    Ich versteh nicht wieso der Codeblocks Compiler da noch das (BYTE*) haben will.


  • Mod

    convert_ schrieb:

    Weiß jemand was der Compiler hier macht? (BYTE*)&KeyData

    Er weint innerlich, weil du ihm befiehlst, still zu sein, obwohl er genau sieht, dass es falsch ist.

    Du übergibst da die Adresse des Zeigers.



  • Du meinst die Funktion: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724923(v=vs.85).aspx
    Dein erstes Beispiel ist korrekt: Die Funktion erwartet einen Zeiger auf const BYTE (BYTE ist Typedef zu unsigned char), du gibst ihr einen. Alles gut.
    Dein zweites Beispiel ist ohne Cast nicht korrekt: Die Funktion erwartet immer noch einen Zeiger auf const BYTE, du gibst ihr aber die Adresse eines Zeigers auf char. Der Typ einer Adresse eines Zeigers auf char ist char**. char** ist ungleich const BYTE*. Der Cast sagt hier soviel "Klappe, Compiler, ich weiß, was ich tue, mach das so wie ich das will". Compiler machts. Programm crasht. Compiler denkt sich "Ich habs dir ja gesagt". Fazit: Du weißt nicht, was du tust, caste nicht. Insbesondere keine C-Style Casts.

    Nachtrag: Selbst wenn du nicht die Adresse des Zeigers übergeben hättest, char* ist immer noch etwas anderes als unsigned char*. Mach es also so wie im ersten Beispiel.

    Nachtrag 2: An deinem zweiten Beispiel ist noch etwas anderes nicht schön: Erstelle keinen Zeiger auf char von einem Stringliteral, es muss ein Zeiger auf const char sein, da du das Literal ja nicht ändern kannst. Ersteres ist nur aus historischen Gründen erlaubt. Aktiviere also Warnungen deines Compilers, der warnt da nämlich vor!

    Editierter Nachtrag 3: Wenn du schon die T-Str-Variante nimmst, nimm auch das TEXT-Makro, sonst haste nämlich Compilerfehler, sobald du Unicode aktivierst.


  • Mod

    convert_ schrieb:

    Bei meinem Codegear Compiler führe ich die Funktion so aus:

    LPCTSTR ValueName = "TestKey";
    	const BYTE *KeyData = "test";
    	RegSetValueEx(phkResult,ValueName,0,REG_SZ,KeyData, strlen(KeyData)+1);
    

    Bei Codeblocks muss ich es aber so machen:

    LPCTSTR ValueName = "TestKey";
    char *KeyData = "test";
    RegSetValueEx(phkResult,ValueName,0,REG_SZ, (BYTE*)&KeyData, strlen(KeyData)+1);
    

    Weiß jemand was der Compiler hier macht? (BYTE*)&KeyData
    Ich denke mal er übergibt die Adresse der Variable KeyData an die Funktion RegSetValueEx. Aber wenn dem so wäre/ist dann müsste ich doch auch schreiben können:

    LPCTSTR ValueName = "TestKey";
    char *KeyData = "test";
    RegSetValueEx(phkResult,ValueName,0,REG_SZ,&KeyData, strlen(KeyData)+1);
    

    Ich versteh nicht wieso der Codeblocks Compiler da noch das (BYTE*) haben will.

    Warum hat den KeyData plötzlich einen anderen Typ? Beide deiner (Codeblocks-)Varianten sind im Übrigen falsch.



  • Pointer werden soweit ich weiss nicht implizit konvertiert, auch wenn der eine Typ ( BYTE ) lediglich ein typedef des anderen ist ( char ).

    Die Funktion erwartet einen const BYTE* als Argument, daher wird der char* den du wahrscheinlich zuerst versucht hast zu übergeben nicht akzeptiert. Wahrscheinlich hätte das Codegear ebenfalls beanstandet, dort hat KeyData allerdings bereits den Typen, den die Funktion erwartet.

    Dein Code enthält allerdings noch einen gravierenden Fehler:
    &KeyData ist nicht vom Typ char* sondern vom Typ char** (Zeiger auf einen Zeiger auf char). Was du also an die Funktion übergibst ist nicht ein Zeiger auf die Zeichenfolge, sondern ein Zeiger auf die (de facto) Speicheradresse an der die Adresse der Zeichenfolge gespeichert ist. Korrekt müsste das Argument so aussehen:
    (BYTE*) KeyData
    oder noch besser (C++-Style, ist schließlich ein C++-Forum):
    reinterpret_cast<BYTE*>(KeyData)

    Gruss,
    Finnegan



  • Finnegan schrieb:

    Pointer werden soweit ich weiss nicht implizit konvertiert, auch wenn der eine Typ ( BYTE ) lediglich ein typedef des anderen ist ( char ).

    Typedefs sind keine eigenen Typen, nur Namen für bereits existierende Typen. Die Zeiger werden dabei tatsächlich nicht konvertiert, aber nur weil es nichts zu konvertieren gibt.
    Wobei BYTE typischerweise ein typedef auf unsigned char ist, und das ist nicht das selbe wie char oder signed char .

    Finnegan schrieb:

    Die Funktion erwartet einen const BYTE* als Argument, daher wird der char* den du wahrscheinlich zuerst versucht hast zu übergeben nicht akzeptiert.

    Das ist vermutlich richtig, da wie gerade erwähnt, BYTE typischerweise ein typedef auf unsigned char ist, und ein char -Zeiger ist natürlich nicht implizit in einen unsigned char -Zeiger konvertierbar.


Anmelden zum Antworten