• ich habe mal eine frage zu variablen und datentypen

    so wie ich das verstanden habe werden die variablen im ram gespeichert und wenn sie gebraucht werden, werden sie wieder ausgelesen. wo sich die variable befindet veraten die zeiger (pointer). nun habe ich eine frage, woher weiß das programm was für ein datentyp der pointer hat?. ich kann ja auch mit einem programm auf die werte von zeigern zugreifen wo ein anderes programm werte abgespeichert hat.

    ich würde mich freuen wenn mir da jemand helfen könnte.
    danke

  • Die Datentypen gibt es nur, um Fehler zu vermeiden. Wenn du dich mit Assembler vertraut machst wirst du sehen, dass du im RAM nicht gerignsten erkennen kannst welchen Datentyp etwas hat oder ob es evtl. sogar ein ausführbarer Code ist.
    Wenn du aber mit C++ etwas schreibst und kompilierst, dann wird das auch wieder zu einer Masse.
    Damit es einfacher ist absturzfrei und fehlerfrei zu programmieren, wurden Datentypen eingeführt. Du kannst im CPU nicht einfach versuchen einen Float + 2 zu rechnen. Da würde ominöse Werte rauskommen. Ebenso gibt es Variablen mit 64 bit oder eben weniger, da können bei Verwechslungen auch komische Werte or bei Pech sogar Abstürze folgen. Damit zu Floats nur mit Floats verrechnest usw. werden Datentypen benutzt.
    Autoit macht das dann einfach für Anfänger und lässt sogar offen ob Zahlen oder Strings gespeichert werden. Dem liegt ein komplexerer Handler zu Grunde, der automatisch die richtigen Funktionen nimmt. Im inneren wird aber immernoch mit Datentypen gehandelt.

    Als Beweis ^^ du kannst in C++ eine float zahl=3; deklarieren und mit float *ptr=&zahl; die Adresse des Floats im ptr speichern. Versuch doch mal int x=*((int*)ptr); danach auszuführen und gib x aus. Es wird nicht 3 sein.

  • Das kommt auf die Programmiersprache an. In C++ (und auch anderen [meist nativ kompilierten] Sprachen) MUSS der Programmierer angeben, welchen Datentyp eine Variable/Pointer hat. Ein Pointer vom Datentyp Integer darf nur auf eine Variable mit dem Datentyp Integer zeigen. Spezialfall: Casting.
    In der Programmiersprache AutoIt wird dies vom AutoIt-Interpreter geregelt. Der Interpreter, welcher in C++ geschrieben ist, denkt mit und weist jeder Variable den richtigen Datentyp automatisch zu. Ausserdem kann er sie untereinander konvertieren ohne dass sich der Programmierer darum kümmern müsste. Der Nachteil davon ist ein Verlust von Geschwindigkeit und auch eine grössere Fehleranfälligkeit von Seiten des Programmieres.

    Anhand des Assemblercodes, welcher die Variable ausliest und schreibt, kann man oftmals den Datentyp erahnen. Dies liegt daran, dass im Assemblercode die Grösse der Variable abzulesen ist.
    Bsp: mov eax, dword ptr [ebx+030].
    Dort wird also ein DWORD [==> 4 Bytes geladen].
    Bsp: mov eax, byte ptr [ebx+030].
    Hier wird nur ein Byte geladen.
    Der Assemblercode sagt allerdings nur etwas über die Grösse und nicht über den Aufbau des Datentyps aus.

    €dit: Zu spät :(

  • @night:
    Der Assemblercode sagt dir im genausten welcher Datentyp das ist. Vom Pointer kannst du es nur nich ableiten.
    Wenn 8 Byte mit fild geladen werden ist es ein 64-bittiger Int, bei 4 Byte fld ist es ein Float. bei mov eax,[0xabcdef] mov eax,[eax] weißt du, dass es ein Pointer war ^^

  • Du kannst vom Assemblercode nicht den genauen Datentyp ableiten. Man kann ihn höchtens durch Reverse Engineering erahnen. Der Datentyp HANDLE belegt zwar 4 Byte, ist aber vom Verwendungszweck her kein Integer.

  • vielen dank. ihr helft mir sehr :)
    sorry wenn ich noch mal störe aber noch eine frage woher weiß dann eine programmiersprache wie groß eine array ist, wird die größe in eine variable gespeichert oder wie?

    danke

  • Hi,
    wie fast zu jedem Thema gab es auch zu diesem schon einige Threads, u.a. diesen

  • Die Arraygröße wird bei Java gespeichert, bei C++ speichert sie der Compiler und gibt ggf. eine Fehlermeldung. Zu Laufzeit wird aber nicht mehr die Größe gespeichert. Da sind alle Daten direkt hintereinander. ein Array ist eigentlich ein Pointer auf den Anfang der Daten (bei C++ und Assembler).

    @night. HANDLE ist kein wirklicher Datentyp. Zugegeben, er hilft wieder Fehler zu vermeiden etc. aber den zu Grunde liegeden Datentyp DWORD erkennt man im Code (#define HANDLE DWORD o.ä. wird es geben)

    EDIT: / PS:
    Deswegen kannst du in C++ auch eine als Pointer deklarierte Variable mit arr[x] ansprechen (als Array) und ein Array-Element als Pointer benutzen (*arr).

  • Arrays sind in C++ so eine Sache.

    Die statischen Arrays sind beim compilen in der Größe bereits festgelegt.

    Code
    int array[10];

    hat immer 10 Elemente.

    Code
    int size = ...;
    int array[size];

    geht nicht.

    Von einer Funktion aus lässt sich auf die Größe nicht zugreifen, dass liegt aber auch daran, dass als Parameter nur ein einzelner pointer auf das erste ELement übergeben wird.

    Normalerweise verwendet man deswegen std::vector. Das ist eine Klasse, die unter anderem auch die Größe speichert.

  • Noch als Zusatz:
    int array[10]; Wird als lokale Variable im Stack gespeichert.
    Aber man kann auch dynamische Größen benutzen und diese zurückgeben. Dazu wird mit new Speicher im Heap alloziiert
    int size=10;
    int *array=new int[size];
    Dann hat man die Größe selber.
    std:vector ist zusätzlich noch dynamisch, man kann also noch ein Arrayelement hinzufügen, ohne das gesamte Array übertragen zu müssen (soweit ich weiß, bin mir nicht 100% sicher)


    EDIT:
    Das ist jetzt schon fast ein richtig guter "Tutorial"-Thread fürs gute Verständnis von Datentypen geworden hier ^^

  • TheShadowAE
    Was standardmäßige Datentypen angeht, hast du wahrscheinlich grundlegend recht. Allerdings kann man nur anhand der Grösse keine signed von unsigned Variablen unterscheiden. Ausserdem sollten die Datentypen char und boolean auch identisch sein.

  • Lange Rede, kurzer Sinn: Man kann den Datentyp nur interpretieren, wenn man ihn nicht kennt.

    Hier ein kleines Beispiel

    Spoiler anzeigen
    [autoit]

    Global $tTestStruct = DllStructCreate("float") ; 4 Byte groß
    Global $pTestStruct = DllStructGetPtr($tTestStruct)
    DllStructSetData($tTestStruct, 1, -20.7) ; schreibe den Float-Wert -20.7 in den Speicher

    [/autoit] [autoit][/autoit] [autoit]

    Global $tInterpretation1 = DllStructCreate("BYTE[4]", $pTestStruct)
    Global $tInterpretation2 = DllStructCreate("short[2]", $pTestStruct)
    Global $tInterpretation3 = DllStructCreate("USHORT[2]", $pTestStruct)
    Global $tInterpretation4 = DllStructCreate("int", $pTestStruct)
    Global $tInterpretation5 = DllStructCreate("UINT", $pTestStruct)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("Interpretation1 - Byte 0: " & DllStructGetData($tInterpretation1, 1, 1) & @CRLF)
    ConsoleWrite("Interpretation1 - Byte 1: " & DllStructGetData($tInterpretation1, 1, 2) & @CRLF)
    ConsoleWrite("Interpretation1 - Byte 2: " & DllStructGetData($tInterpretation1, 1, 3) & @CRLF)
    ConsoleWrite("Interpretation1 - Byte 3: " & DllStructGetData($tInterpretation1, 1, 4) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite(@CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("Interpretation2 - short 0: " & DllStructGetData($tInterpretation2, 1, 1) & @CRLF)
    ConsoleWrite("Interpretation2 - short 1: " & DllStructGetData($tInterpretation2, 1, 2) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite(@CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("Interpretation3 - USHORT 0: " & DllStructGetData($tInterpretation3, 1, 1) & @CRLF)
    ConsoleWrite("Interpretation3 - USHORT 1: " & DllStructGetData($tInterpretation3, 1, 2) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite(@CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("Interpretation4 - int: " & DllStructGetData($tInterpretation4, 1) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite(@CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("Interpretation5 - UINT: " & DllStructGetData($tInterpretation5, 1) & @CRLF)

    [/autoit]
  • ...und zu allem Überfluss schlägt auch noch die Endianess zu!
    Es gibt wohl kaum jemanden, der nicht daran schon verzweifelt ist^^

    [autoit]

    $byte_struct = DllStructCreate("byte[4]") ;byte struktur erstellen
    $word_struct = DllStructCreate("word[2]", DllStructGetPtr($byte_struct)) ;word struktur an der adresse der byte-struktur erstellen
    $dword_struct = DllStructCreate("dword", DllStructGetPtr($byte_struct)) ;dword struktur an der adresse der byte-struktur erstellen

    [/autoit][autoit][/autoit][autoit]

    DllStructSetData($dword_struct, 1, 0xAABBCCDD) ;dword schreiben

    [/autoit][autoit][/autoit][autoit]

    ConsoleWrite("DWORD 0xAABBCCDD => dword " & Hex(DllStructGetData($dword_struct, 1), 8) & @CRLF)

    [/autoit][autoit][/autoit][autoit]

    ConsoleWrite("DWORD 0xAABBCCDD => word " & Hex(DllStructGetData($word_struct, 1, 1), 4) & Hex(DllStructGetData($word_struct, 1, 2), 4) & @CRLF)

    [/autoit][autoit][/autoit][autoit]

    ConsoleWrite("DWORD 0xAABBCCDD => byte " & Hex(DllStructGetData($byte_struct, 1, 1), 2) & Hex(DllStructGetData($byte_struct, 1, 2), 2) & Hex(DllStructGetData($byte_struct, 1, 3), 2) & Hex(DllStructGetData($byte_struct, 1, 4), 2) & @CRLF)

    [/autoit][autoit][/autoit][autoit][/autoit]