Invalid Conversion



  • Hallo C++ Community,

    wie der ein oder andere von euch vielleicht schon bemerkt hat, bin ich recht neu in dieser Community und habe auch erst vor 2 Wochen mit der C++ Programmierung angefangen. Grundlagen der Programmierung kenne ich jedoch bereits durch PHP, was ich schon seit 3 Jahren programmiere.

    An PHP ist das schöne, dass der Datentyp einer Variable automatisch vom Inhalt abhängig festgelegt wird, was in C++ nicht der Fall ist, und mir auch leider so einige Probleme bereitet...

    So nun aber zu meinem Problem:
    Ich möchte eine kleine Konsole Application schreiben, die mir einen Registry Key erstellt. Jedoch bekomme ich einen Fehler. Den Grundcode habe ich aus den FAQ's in diesem Forum (Ja ich habe Gegoogelt!)
    http://www.c-plusplus.net/forum/topic,39373.html

    So folgenden Code habe ich mir daraus gebastelt:

    #include <iostream>
    #include <windows.h>
    #include <stdio.h>
    
    int main(int argc, char * argv[])
    {
        HKEY hKey;
        RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",0,0,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,0);
    
        BYTE cString[]="Hallo, das ist der eigentliche Wert, der unter dem Namen EintragsName gespeicehrt wird";
        RegSetValueEx(hKey,"EintragsName",0,REG_SZ,cString,strlen(cString)+1);
    
        RegCloseKey(hKey);
    }
    

    Jedoch erhalte ich folgende Fehlermeldung:

    G:\C++\edit_registry\main.cpp||In function `int main(int, char**)':|
    G:\C++\edit_registry\main.cpp|51|error: invalid conversion from `BYTE*' to `const char*'|
    G:\C++\edit_registry\main.cpp|51|error:   initializing argument 1 of `size_t strlen(const char*)'|
    ||=== Build finished: 2 errors, 0 warnings ===|
    

    Wenn ich den Typ von BYTE cString zu char cString ändere, bekomme ich folgende Meldung:

    G:\C++\edit_registry\main.cpp||In function `int main(int, char**)':|
    G:\C++\edit_registry\main.cpp|51|error: invalid conversion from `char*' to `const BYTE*'|
    G:\C++\edit_registry\main.cpp|51|error:   initializing argument 5 of `LONG RegSetValueExA(HKEY__*, const CHAR*, DWORD, DWORD, const BYTE*, DWORD)'|
    ||=== Build finished: 2 errors, 0 warnings ===|
    

    Also lustigerweise genau das gleiche, nur andersrum. Ich würde mich wirklich freuen, wenn ihr mir helfen könnt, habe nämlich jetzt schon 3 Tage lang gegoogelt bis ich überhaupt was für mich brauchbares gefunden hatte 🙂

    Desweiteren würde mich mal interessieren, was der Unterschied zwischen char und char* ist...

    Ich bedanke mich schonmal im voraus,
    liebe Grüße
    Patrick


  • Mod

    Sag doch mal, was ein BYTE ist. strlen erwartet ein char*, RegSetValueEx erwartet ein BYTE*. Und anscheinend ist BYTE kein einfaches typedef für char. Ist BYTE eventuell ein unsigned char? Falls BYTE für unsigned char steht, kannst du mit einem vorsichtig gesetzten reinterpret_cast<char*>(cString) den C-String doch an strlen übergeben, aber bitte versprich, dass du reinterpret_cast danach nie wieder benutzt, ohne gründlich darüber nachzudenken, was da überhaupt passiert.

    Übrigens: char ist ein, nun ja, ein char und char* ist ein Zeiger auf einen (oder oftmals auch mehrere) chars. Was ein Zeiger ist, findest du in jedem guten Buch zur Programmierung erklärt.



  • Patistar schrieb:

    An PHP ist das schöne, dass der Datentyp einer Variable automatisch vom Inhalt abhängig festgelegt wird, was in C++ nicht der Fall ist, und mir auch leider so einige Probleme bereitet...

    Lustig. Genau das verabscheue ich an PHP und macht es für mich zu einer der miserabelsten Sprachen überhaupt.



  • Janjan schrieb:

    Patistar schrieb:

    An PHP ist das schöne, dass der Datentyp einer Variable automatisch vom Inhalt abhängig festgelegt wird, was in C++ nicht der Fall ist, und mir auch leider so einige Probleme bereitet...

    Lustig. Genau das verabscheue ich an PHP und macht es für mich zu einer der miserabelsten Sprachen überhaupt.

    Ist ja nicht nur in PHP so. Ich komm damit aber auch überhaupt nicht zurecht. Irgendwann (bzw. ziemlich schnell) weiß man überhaupt nicht mehr was was ist. Man muss halt aufpassen und das überlas sich lieber dem Compiler.

    BYTE ist hier wie shcon erwähnt irgendeine Typdefinition für irgendetwas anders (wahrschienlcih unsigned char). Wenn du in Visual Studio arbeitest, kannst du mal euf BYTE zeigen f12 drücken und dann hüpft er zu einer Zeile wo steht:
    typedef unisgned char BYTE;
    o.ä.

    Die einzige Zeile C++ ist hier übrigens
    #include <iostream>



  • Und was soll ich für BYTE bei der Variablen deklaration schreiben? char?
    Das klappt auch nicht so ganz...

    Ich habe mich direkt mal über "Zeiger" und deine "reinterpret_cast<char*>" informiert. Ein Zeiger zeigt also auf eine Variable, man erstellt ihn anscheinend mit dem &-Zeichen, wie in PHP auch, nur dass man in PHP bei einer Variable nicht angeben muss, dass sie ein Zeiger ist, wie man in PHP auch den Dateityp nicht angeben muss.

    reinterpret_cast ist das gefährlichste Cast und man soll es nur gezielt einsetzten, hab ich erfahren. Warum es gefährlich ist, ist mir allerdings nicht klar.

    Mein aktueller Code:

    #include <iostream>
    #include <windows.h>
    #include <stdio.h>
    
    int main(int argc, char * argv[])
    {
        HKEY hKey;
        RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",0,0,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,0);
    
        char cString[]="Hallo, das ist der eigentliche Wert, der unter dem Namen EintragsName gespeicehrt wird";
        RegSetValueEx(hKey,"EintragsName",0,REG_SZ,reinterpret_cast<char*>(cString),strlen(cString)+1);
    
        RegCloseKey(hKey);
    }
    

    und der Fehler:

    G:\C++\edit_registry\main.cpp||In function `int main(int, char**)':|
    G:\C++\edit_registry\main.cpp|51|error: invalid conversion from `char*' to `const BYTE*'|
    G:\C++\edit_registry\main.cpp|51|error:   initializing argument 5 of `LONG RegSetValueExA(HKEY__*, const CHAR*, DWORD, DWORD, const BYTE*, DWORD)'|
    ||=== Build finished: 2 errors, 0 warnings ===|
    

    Wenn ihr doch alle Fans von diesen ganzen Variablentypen seid, könnt ihr mir doch sicherlich weiterhelfen 😉

    Ich verstehe gar nicht, wie man die automatischen Variablentypen nicht mögen kann, mich bringt das in C++ um Kopf und Kragen 😉

    Liebe Grüße
    Patrick



  • Patistar schrieb:

    Ich verstehe gar nicht, wie man die automatischen Variablentypen nicht mögen kann, mich bringt das in C++ um Kopf und Kragen 😉

    Du bemühst dich aber auch nicht wirklich.

    strlen erwartet einen char*
    RegSetValueEx erwartet einen BYTE*


  • Mod

    RegSetValueEx(hKey,"EintragsName",0,REG_SZ,reinterpret_cast<char*>(cString),strlen(cString)+1);
    

    Umgekehrt:

    RegSetValueEx(hKey,"EintragsName",0,REG_SZ,cString,strlen(reinterpret_cast<char*>(cString))+1);
    

    Versuch noch einmal die Fehlermeldungen zu verstehen, dann dürfte klar werden, welche Funktion was will.

    Reinterpret_cast ist deswegen gefährlich, weil man damit sämtliche Sicherheitsvorkehrungen des Typensystems (die man in C++ als Feature und nicht, wie du, als Hindernis ansieht) ausschaltet.


  • Mod

    edit: Schon wieder Doppelpost. Irgendwie funktioniert bei mir das Forum in letzter Zeit nicht richtig, eigentlich sollte dies doch von der Software verhindert werden.



  • //EDIT: Ihr seid wirklich eine so super schnelle Community, dass meine Antwort nichtmehr aktuell ist 😉


  • Mod

    Patistar schrieb:

    //EDIT: Ihr seid wirklich eine so super schnelle Community, dass meine Antwort nichtmehr aktuell ist 😉

    Mach dir aber trotzdem Mal Gedanken, warum das reinterpret_cast um cString und nicht um strlen stehen muss. Das ist eine wichtige Erkenntnis.



  • So ich möchte mich erstmal vielmals bei euch bedanken, ihr seid eine großartige Community!

    @SeppJ: Okay vielen Dank für deine Erklärung, ich werde auch Versuchen mich an die Typen zu gewöhnen und reinterpret_cast() so wenig wie möglich zu verwenden.
    Mein 1. Fehler war wohl, dass ich beim falschen Parameter den Typ geändert habe und mein letzerer Fehler war nur ein kleiner Denkfehler...

    Hatte ausversehen:

    reinterpret_cast<char*>strlen((cString))
    

    geschrieben, aber hier würde ja mein Ergebnis, was eine INT Zahl ist, in einen char umgewandelt werden, was natürlich völliger Blödsinn ist, und das wäre selbst in PHP nicht gegangen 😃

    Habe das ganze Skript gerade ausgeführt und es funktioniert Prima, möchte mich nochmal bedanken, so schnelle und qualitative Hilfe bekommt man in kaum einem anderen Forum 😉

    Liebe Grüße
    Patrick



  • So nun hab ich doch noch einmal eine allgemeine Frage:
    Woher weiß ich, welchen Variablentyp ich brauche?

    Ein klassisches Beispiel von mir:

    char* appdata = getenv("appdata");
    CopyFile("aaabc.txt", appdata+"\\Microsoft\\Windows\\aaabc.txt",1);
    

    In diesem Beispiel habe ich schon herausgefunden, dass ein char appdata nicht geht, sondern ich eine char* appdata benötige. Ich vermute mal stark, dass es daran liegt, dass ich ja nur auf die Funktion getenv verweise bzw. zeige.

    Jedoch mag der meinen Binäroperator + nicht so ganz und sagt, dass ich den nicht verwenden darf auch wenn ich reinterpret_cast<char*>("\\Microsoft...") verwende.

    Wenn ich das reinterpret_cast weglasse, was ich ja gerne möchte, erhalte ich den Fehler, dass ihm const char[29] und char* nicht passen um diese zuzsammenzufügen:
    (G:\C++\keylogger_installer\main.cpp|26|error: invalid operands of types `char*' and `const char[29]' to binary `operator+'|)

    Was ist der Unterschied zwischen const char[29] und char* oder allgemeine zwischen const char und char und warum funktioniert das so nicht.

    const char[29] ist ein Array oder etwas in der Art vermute ich...



  • Es gibt kein +Operator, der links und rechts einen char* akzeptiert auch kein char[]. So etwas gibt es einfach nciht. So ein Operator ist nur für die C++ Klasse std::string definiert.

    #include <string>
    
    int main()
    {
      std::string appdata = getenv("appdata");
      std::string file = appdata + "\\Mikroschuft\\1.txt";
      CopyFile("aabc.txt", file.c_str());
    }
    

    Die string Klasse kann sowas. Darum sollte man in C++ für Zeichenketten immer std::string benutzen.

    string ist übrigens eine Templateklasse und kann daher nicht nur mit Ketten von chars umgehen. Man könnte damit z.B. auch sowas machen

    typedef std::basci_string<BYTE> byte_string;
    

Anmelden zum Antworten