|
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
CommLan
Anmeldungsdatum: 23.10.2015 Beiträge: 40 Wohnort: hinterm Mond
|
Verfasst am: 22.11.2020, 18:25 Titel: Pointer und Allocate |
|
|
Hallo ins Forum,
nach langer Zeit gibts mal wieder ein Lebenszeichen, direkt mit dem wehleidigen Thema Pointer.
Meine geistige Feindschaft zur Logik von bestimmten Pointerkonstrukten wird wohl nie enden.
Aber. zum Thema, ich habe hier einen Code und dazu eine Frage:
Code: |
TYPE UDT_TestListRecord
VAR_INT_NextPointer AS INTEGER
VAR_INT_PrevPointer AS INTEGER
VAR_INT_Parameter1 AS INTEGER
VAR_INT_Parameter2 AS INTEGER
END TYPE
DIM AS UDT_TestListRecord PTR TEST
TEST = ALLOCATE(24)
TEST->VAR_INT_NextPointer = 1
TEST->VAR_INT_PrevPointer = 2
TEST->VAR_INT_Parameter1 = 3
PRINT SIZEOF(*TEST)
PRINT TEST->VAR_INT_NextPointer
PRINT TEST->VAR_INT_PrevPointer
PRINT TEST->VAR_INT_Parameter1
|
Die Ausgabe dazu sieht so aus:
Warum sagt SIZEOF, dass ich 32 Byte reserviert hätte ? Ist das eine Anomalie von Free Basic und soll mich vor falschem allozieren schützen ? Oder bin ich gerade auf dem Holzweg ?
Man kann auch auf diesen Speicher ohne Probleme zugreifen. Meiner Meinung nach sollte das aber doch eigentlich zu einem Segfault führen, oder ?
Die Ironie, wenn ich ALLOCATE nicht benutze, passiert das auch "wie es soll". Wo kommt dieser eigentlich nicht allozierte Speicher her ? |
|
Nach oben |
|
|
ThePuppetMaster
Anmeldungsdatum: 18.02.2007 Beiträge: 1837 Wohnort: [JN58JR]
|
Verfasst am: 22.11.2020, 21:05 Titel: |
|
|
Ein Pointer ist so groß, wie das System "Bit"-Definiert ist.
32-Bit System = 32-Bit Pointer
64-Bit System = 64-Bit Pointer
Bzw. Wenn du 32-Bit Compiler nutzt, dann gibts auch nur 32Bit
Ein Pointer "Zeigt" ja auch nur die die Speicherstelle, und IST nicht die Speicherstelle selbst.
Code: | Dim TPointer as Byte Ptr
Print SizeOf(TPointer)
Print SizeOf(Any Ptr)
Dim TByte as Byte
Print SizeOf(TByte)
Print SizeOf(Byte)
|
Wenn du die Größe des Speicher wissen willst, welcher aus dem UDT kommt, dann ...
Code: |
Print SizeOf(UDT-Name)
|
PS: Der "FIELD" Parameter ist in zusammenhang mit einem UDT eventuell auch für dich Relevant -> https://www.freebasic-portal.de/befehlsreferenz/field-236.html
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
|
CommLan
Anmeldungsdatum: 23.10.2015 Beiträge: 40 Wohnort: hinterm Mond
|
Verfasst am: 22.11.2020, 21:23 Titel: |
|
|
Danke für die schnelle Antwort, aber ich denke du hast dich verlesen oder ich bin dumm.
Es geht um Byte, nicht um Bit. Als Info, ich habe ein 64 Bit - System.
Wenn bei dem Beispiel herauskäme, dass ich nicht unter 8 Byte komme, dann würde mich das tatsächlich nicht wundern. Ein bisschen was weiß ich ja auch noch.
Aber es geht hier um 24 bzw. 32 Byte. Und da liegt für mich gerade die Frage, warum ALLOCATE sich hier nicht nach dem (zu kleinen) Parameter, sondern offensichtlich nach dem, worauf der Pointer zeigt, richtet.
Weil ich würde bei der jetzigen Anwendung gerne ohne Speicherlecks (mag man jetzt verstehen wie man will, wirkt ohne Kontext unlogisch, ich weiß) schreiben und da stören solche Sachen schon irgendwie. |
|
Nach oben |
|
|
ThePuppetMaster
Anmeldungsdatum: 18.02.2007 Beiträge: 1837 Wohnort: [JN58JR]
|
Verfasst am: 22.11.2020, 21:32 Titel: Re: Pointer und Allocate |
|
|
OK ...
CommLan hat Folgendes geschrieben: |
Code: |
TYPE UDT_TestListRecord
VAR_INT_NextPointer AS INTEGER
VAR_INT_PrevPointer AS INTEGER
VAR_INT_Parameter1 AS INTEGER
VAR_INT_Parameter2 AS INTEGER
END TYPE
|
|
Code: | Print SizeOf(Integer) |
Integer sind Systemabhängig und sind auf 32Bit Systeme 32/8 = 4 Byte Groß.
Auf 64Bit Systeme sind es 64/8 = 8 Byte
4 Integer auf 64Bit System = 4Stk. * 64(Bit-System) / 8 (Bit pro Byte) = 32 Byte
EDIT Gerade gesehen, was du genau meinst .. ich check das fix...
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
|
ThePuppetMaster
Anmeldungsdatum: 18.02.2007 Beiträge: 1837 Wohnort: [JN58JR]
|
Verfasst am: 22.11.2020, 21:42 Titel: Re: Pointer und Allocate |
|
|
OK .. hab gesehen, was du meinst, bzw. worüber du dich wunderst.
Hier
Code: |
TYPE UDT_TestListRecord
'...
END TYPE |
Definierst du einen Typ, dessen Größe durch seinen Inhalt definiert ist.
Hier
Code: |
DIM AS UDT_TestListRecord PTR TEST
|
Definierst du eine Variable welche generell eigentlich nur ein Pointer auf den Bereich ist (nicht durch das PTR). Die Größe dieses Speicherst gibst du mit der Angabe des TYPEs an. In deinem Fall "UDT_TestListRecord".
Du Definierst die Variable als Poitnervariable mit PTR
Jetzt Willst du die Größer mit SizeOf herausfinden. Da die Betriebssysteme (im generellem) keine Informationen über die Größe des Alloziiertem Speichers dem Programm zur verFügung stellen, muss FB beim Kompilieren die Größe anhand deiner Definition ermitteln.
Faktisch wird das zu einem
Code: | SizeOf(UDT_TestListRecord) |
Wenn du manuell alloc'st, dann begehst du faktisch ein MEM-Leak.
Du solltest also IMMER Allocate(SizeOf(UDT)) nutzen, und, im idealfall auch CAllocate (um die SPeicherstelle auch zu "cleenen").
(Schon Alleindeswegen, um 32Bit / 64Bit /... System kompatibilität zu gewährleisten. Anderenfalls musst du bei jedem Alloc erstmal prüfen, was für ein System du nutzt, udn welche Variablen du in dem Typ definiert hast, und und und noch vieles mehr. -> Ganz Ungünstig
Wenn du 24 Bytes auf 32 Byte "mappst", kann es in der tat zu einem Memleak führen.
Unter Linux kannst du das mit
Code: | fbc -g test.bas && valgrind ./test |
erkennen und testen (apt-get install valgrind)
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4597 Wohnort: ~/
|
Verfasst am: 22.11.2020, 22:14 Titel: |
|
|
In dem Fall eines UDT-Pointers kannst du auch mit NEW und DELETE arbeiten. Vorteil: Die reservierte Speichergröße passt dann auch, und du kannst außerdem gleich einen Konstruktor aufrufen. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
ThePuppetMaster
Anmeldungsdatum: 18.02.2007 Beiträge: 1837 Wohnort: [JN58JR]
|
Verfasst am: 22.11.2020, 22:19 Titel: |
|
|
Wenn du
Code: | TEST->VAR_INT_Parameter2 = 4 |
durchfürst, könnte es sogar zu einem Crash kommen. Da dies der Speicherbereich ist, der außerhalb deines Alloc's liegt.
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
|
CommLan
Anmeldungsdatum: 23.10.2015 Beiträge: 40 Wohnort: hinterm Mond
|
Verfasst am: 23.11.2020, 20:46 Titel: |
|
|
Ich habe gerade gesehen, dass der eigentliche Fehler anders funktioniert. Das UDT muss so aussehen:
Code: |
TYPE UDT_TestListRecord
VAR_BYT_Test AS UBYTE
VAR_INT_NextPointer AS UINTEGER
VAR_INT_PrevPointer AS UINTEGER
VAR_INT_Parameter1 AS UINTEGER
VAR_INT_Parameter2 AS UINTEGER
END TYPE
|
Mit ALLOCATE reserviert man jetzt 25 Byte.
Jetzt ist ja die Sache, er wird 32 Byte allozieren (Busbreite). Es werden aber 33 benötigt. Weist man Parameter 2 jetzt z.B. die Zahl 18446744073709551615 zu, werden alle 8 Byte zum darstellen defintiv benötigt, dass 33igste Byte wird jetzt also definitiv angesprochen und überschrieben.
Es crasht aber nix. Ich lasse das gerade hier in Endlosschleife laufen und es passiert orignal nichts. Nicht einmal die Zahl verändert sich.
[EDIT] Ich habe jetzt auch allen Variablen ihren Maximalwert zugewiesen um zu prüfen dass das UDT nicht anders gespeichert wird, es ändert sich aber auch dann nichts.
[EDIT] @ThePuppetMaster: Aber dass sizeof den Wert nicht zurückgeben kann wusste ich tatsächlich vor längerem sogar mal, habs aber irgendwie verdrängt |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4597 Wohnort: ~/
|
Verfasst am: 23.11.2020, 21:28 Titel: |
|
|
Wenn du den reservierten Bereich minimal überschreitest, kann es durchaus sein, das nichts crasht, weil der unerlaubt beschriebene Bereich noch innerhalb des deinem Programm zugesicherten Speicherbereich liegt. Das macht die Sache aber nicht besser - denn dann besteht die Gefahr, dass du unbemerkt andere Variablen deines Programms überschreibst; kurz gesagt gefährdet es die Integrität deines Programms. Ein Segfault ist fast schon das beste, was passieren kann, denn dann weiß man, woran man ist. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1211 Wohnort: Ruhrpott
|
Verfasst am: 23.11.2020, 23:23 Titel: |
|
|
CommLan hat Folgendes geschrieben: | Mit ALLOCATE reserviert man jetzt 25 Byte.
Jetzt ist ja die Sache, er wird 32 Byte allozieren (Busbreite). Es werden aber 33 benötigt. Weist man Parameter 2 jetzt z.B. die Zahl 18446744073709551615 zu, werden alle 8 Byte zum darstellen defintiv benötigt, dass 33igste Byte wird jetzt also definitiv angesprochen und überschrieben. | Sieht so aus, als herrsche da einiges an Begriffsverwirrung.
Dein UDT besteht aus 4 UIntegern zu je 8 Byte und einem UByte zu einem Byte. Macht zusammen 4 * 8 + 1 = 33 Byte. SIZEOF wird aber jetzt einen Wert von 40 melden (8 * 5), und genau diese Menge an Speicher mußt du deinem UDT auch mit ALLOCATE reservieren. Dieses "Aufrunden" auf ganze INTEGER bringt einen enormen Vorteil bei der Zugriffsgeschwindigkeit, da kann man einige ungenutzte Bytes ruhig in Kauf nehmen, und (auch) deshalb solltest du die Berechnung des tatsächlichen Speicherbedarfs dem Compiler überlassen. Reservierst du stattdessen nur 25 Byte (wie kommst du überhaupt auf diesen Wert?), ist das schlicht und einfach ein Programmierfehler, und zwar einer der ganz gemeinen Sorte, der möglicherweise nur sporadisch auftritt und vielleicht sogar lange Zeit nicht bemerkt wird:
Code: | TYPE UDT_TestListRecord
VAR_BYT_Test AS UBYTE
VAR_INT_NextPointer AS UINTEGER
VAR_INT_PrevPointer AS UINTEGER
VAR_INT_Parameter1 AS UINTEGER
VAR_INT_Parameter2 AS UINTEGER
END Type
DIM AS UDT_TestListRecord PTR TEST
DIM AS UDT_TestListRecord PTR TEST2
TEST = ALLOCATE(12)
TEST2 = ALLOCATE(12)
TEST->VAR_INT_NextPointer = 1
TEST->VAR_INT_PrevPointer = 2
TEST->VAR_INT_Parameter1 = 3
TEST2->VAR_INT_NextPointer = 10
TEST2->VAR_INT_PrevPointer = 20
TEST2->VAR_INT_Parameter1 = 30
PRINT SIZEOF(*TEST)
?
PRINT TEST->VAR_INT_NextPointer
PRINT TEST->VAR_INT_PrevPointer
PRINT TEST->VAR_INT_Parameter1
? "---"
PRINT TEST2->VAR_INT_NextPointer
PRINT TEST2->VAR_INT_PrevPointer
PRINT TEST2->VAR_INT_Parameter1
Sleep
DeAllocate test
DeAllocate test2 |
Das Programm stürzt nicht ab, weil der angesprochene Speicherbereich ja tatsächlich für dieses Programm reserviert ist, aber es werden einige falsche Speicherstellen überschrieben.
Und 18446744073709551615 befindet sich innerhalb des Bereichs der mit 8 Byte darstellbaren Zahlen. Warum sollte das 33. Byte dadurch überschrieben werden?
Ein Speicherleck entsteht übrigens immer nur dann, wenn du vergisst, den reservierten Speicher wieder freizugeben (Stichwort: DEALLOCATE), wenn er nicht mehr gebraucht wird.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
ThePuppetMaster
Anmeldungsdatum: 18.02.2007 Beiträge: 1837 Wohnort: [JN58JR]
|
Verfasst am: 24.11.2020, 06:52 Titel: |
|
|
CommLan hat Folgendes geschrieben: | Ich habe gerade gesehen, dass der eigentliche Fehler anders funktioniert. Das UDT muss so aussehen:
Code: |
TYPE UDT_TestListRecord
VAR_BYT_Test AS UBYTE
VAR_INT_NextPointer AS UINTEGER
VAR_INT_PrevPointer AS UINTEGER
VAR_INT_Parameter1 AS UINTEGER
VAR_INT_Parameter2 AS UINTEGER
END TYPE
|
|
Versuch es mal hiermit:
Code: |
TYPE UDT_TestListRecord FIELD 1
VAR_INT_NextPointer AS UINTEGER
VAR_INT_PrevPointer AS UINTEGER
VAR_INT_Parameter1 AS UINTEGER
VAR_INT_Parameter2 AS UINTEGER
VAR_BYT_Test AS UBYTE
END TYPE
|
Dann sollts auch Krachen beim zugriff auf die Byte-Variable mit Werte größer 255
@grindstone ... ich glaube nicht, das der Speicherbereich noch im App-Bereich liegt, da es nachträglich alloct wird, sprich, wärend der Ausführung. Ich vermute eher, das wie du schon geschrieben hast, es einfach am FIELD liegt, und das byte auf int aufgerundet wird.
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1211 Wohnort: Ruhrpott
|
Verfasst am: 24.11.2020, 13:00 Titel: |
|
|
ThePuppetMaster hat Folgendes geschrieben: | Dann sollts auch Krachen beim zugriff auf die Byte-Variable mit Werte größer 255 |
Ich glaube nicht, daß es kracht. Bei einer Überschreitung des Wertebereichs werden die führenden Bits abgeschnitten, die nachfolgenden Speicherstellen werden nicht korrumpiert. Offenbar wird intern vor einem Schreibzugriff der Wert auf den Zieldatentyp gecastet: Code: | TYPE UDT_TestListRecord
VAR_BYT_Test AS UBYTE
VAR_INT_NextPointer AS UINTEGER
VAR_INT_PrevPointer AS UINTEGER
VAR_INT_Parameter1 AS UINTEGER
VAR_INT_Parameter2 AS UInteger
END Type
DIM AS UDT_TestListRecord PTR TEST
TEST = ALLOCATE(SizeOf(UDT_TestListRecord))
test->VAR_INT_NextPointer = 0
test->VAR_BYT_Test = 255
test->VAR_BYT_Test += 5
? test->VAR_BYT_Test
? test->VAR_INT_NextPointer
Sleep |
@CommLan: Die FB - Pointerarithmetik bietet übrigens noch einige weitere Überraschungen: Code: | TYPE UDT_TestListRecord
VAR_BYT_Test AS UBYTE
VAR_INT_NextPointer AS UINTEGER
VAR_INT_PrevPointer AS UINTEGER
VAR_INT_Parameter1 AS UINTEGER
VAR_INT_Parameter2 AS UInteger
END Type
DIM AS UDT_TestListRecord PTR TEST
DIM AS UDT_TestListRecord PTR TEST2
TEST = ALLOCATE(SizeOf(UDT_TestListRecord))
TEST2 = ALLOCATE(SizeOf(UDT_TestListRecord))
? test
? test2
? test2 - test
Sleep |
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
CommLan
Anmeldungsdatum: 23.10.2015 Beiträge: 40 Wohnort: hinterm Mond
|
Verfasst am: 11.12.2020, 15:00 Titel: |
|
|
Hallo,
ich wollte mich dann doch mal zurück melden, weil doch noch einiges passiert ist.
Die Sache ist, wofür das genau gedacht ist, ist schwer zu erklären und ich will da auch garnicht zu viel von erzählen, weil es noch ein ungelegtes Ei ist, was eventuell sogar scheitern könnte. Was ich aber sagen kann ist, dass diverse Sonderbedingungen herrschen müssen, die mir nur leider in dem Projekt das Leben schwer machen.
Bedeutet also, wenn ich z.B. sage, dass ich manuell allozieren muss und nicht nach Datentypen oder Allocate statt Callocate verwenden muss, dann hat das schon Gründe und hat tatsächlich nix mit verwirrung oder ähnlichem zu tun, auch wenn das hier an der Fragestellung so aussieht - weil das mit SIZEOF eigentlich Grundwissen im Zusammenhang mit Allocate ist.
Den Krieg mit meinem Pointer - Problem habe ich schon in Angriff genommen, es macht langsam klick, aber es gibt vieles, wo ich noch nicht durchsehe. Da heißt es wirklich herumprobieren und verstehen gerade, aber ich bin dabei.
Hier in diesem Thread ging es ja ursprünglich um das vermeintlich merkwürdige Verhalten von allocate mit sizeof. Mir ist es wirklich (wie so vieles) entfallen, dass man den allozierten Speicherbereich nicht erfragen kann - ich weiß das eigentlich. Ich hab das auch schon in C durchexerziert mit dem selben Ergebnis, aber bin nicht selbst drauf gekommen, warum das so war.
Deswegen Danke an alle für die Hilfe, meine Erinnerung aufzufrischen. Wie gesagt, ich kann da im Moment noch nicht viel drüber schreiben, wo das alles noch hinführt.
Ich muss das deswegen auch immer ein wenig anders verpacken, wodurch sich Fehler sowohl in Fragestellung als auch Beispielcode einschleichen. Ich mach das so, damit das alles nicht noch mehr Verwunderung herbeiführt als ohnehin schon.
Wen es interessiert / Sidefact:
Ihr denkt wahrscheinlich, ich komme von irgendwo als Anfänger in allem dahergelaufen, habe eine hohe Meinung von mir weil ich vermeintlich einen 3 - Tage - Dulli - Python - Kurs absolviert habe, in Informatik an der Schule damit nerven konnte, immer der Einser - Schüler gewesen zu sein und meinen Eltern mal den Rechner frisch installiere bzw. mich cool fühle, weil ich weiß, wie man die Recovery disk - oder für die ganz professionellen - wie man ne frische Installation so halb bedienen kann bzw. auch eigenständig rausfinde, wenn mal wieder ne WD - Festplatte im Lappi krepiert ist - auch wegen meinen Fragen - ich will damit nicht angeben sondern nur einen Eindruck vermitteln - dem ist nicht so.
Ich habe mehr als 10 Jahre Erfahrungen besonders im Hardwaresegement die bis zum 386 (und teilweise, da lerne ich gerade, auch weiter) zurückreichen und hab hier auch einen riesigen Pool an Hardware und Möglichkeiten. Auch das nötige Hintergrundwissen ist vorhanden, wie was im Gesamtsystem Computer bzw. eher Prozessor funktioniert und wie die Zusammenhänge liegen. Ich kann im Prinzip meinen eigenen Computer entwickeln, wenn ich wöllte.
Es ist nur so, dass Programmierung an manchen stellen für mich hakelig ist, weil ich manche Darstellungen nicht ganz verstehe - ein Kapitel davon sind z.B. die Pointer, weil ich nicht ganz nachvollziehen kann, was da intern z.B. eigentlich passiert - weil das für mich nicht ganz intuitiv ist bzw. ich das nicht auf die Funktionsweisen vom Computer an sich zurückführen kann, weil es teilweise zu abstrakt demgegenüber ist.
Ich zäume gerne manche Pferde halt von hinten auf. Ich weiß wie die Hardware im Detail funktioniert und lerne hier in dem Fall, wie die Programmiersprache im entferntesten Sinne dadrauf läuft, welche Bitmuster entstehen, was genau berechnet wird etc.
Ich lerne auch zu großen Teilen autodidaktisch, was mir das Leben einerseits schwerer macht, mir aber ein besseres Verständnis von allem liefert, als wenn mir das jemand beibringt. Ich habe genau deswegen dann nur manch dumme fragen, die ich euch dann zu eurem und nachträglich auch meinem Leidwesen zumuten muss, weil ich den Bogen selbst nicht ganz fange. |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|