Bit in Pointer speichern
-
Hallo!
Ich will aus Platznot ein Bit eines Pointers verwenden, um einen Zustand darin
zu speichern. Der Pointer wird aber noch gebraucht. IMHO sind Pointer auf
Linux/Windows, 32/64 bit, gerade. Stimmt das immer (und warum)? Dann kann
ich nämlich das niederwertigste Bit des Pointers dazu verwenden.Wenn schon schmutzig, dann wenigstens sauber. Wie würde man den Pointer ent-
sprechend umbiegen? ptr=ptr|1 geht nicht. Static Cast nach unsigned long, dann
+1, dann static cast in den ursprünglichen Typ?Danke,
-
ptr1 schrieb:
Ich will aus Platznot ein Bit eines Pointers verwenden
Aha. Unter Linux und Windows zu wenig Speicherplatz...
, um einen Zustand darin
zu speichern. Der Pointer wird aber noch gebraucht.Und wo merkst du dir, ob in dem Bit das du geändert hast eine 0 oder eine 1 war?
IMHO sind Pointer auf
Linux/Windows, 32/64 bit, gerade. Stimmt das immer (und warum)?Wenn du damit meinst, dass sie auf 64-Bit Win/Linux 64 Bit groß sind und auf 32-Bit Win/Linux 32, dann: Ja. Und darum. Ist eben einfach so.
Wenn du damit meinst auf Linux 32 Bit, auf Windows 64 Bit, dann nein.
Dann kann
ich nämlich das niederwertigste Bit des Pointers dazu verwenden.Wieso gerade dieses?
Wenn schon schmutzig, dann wenigstens sauber.
Soso

Wie würde man den Pointer ent-
sprechend umbiegen? ptr=ptr|1 geht nicht. Static Cast nach unsigned long, dann
+1, dann static cast in den ursprünglichen Typ?Da muss man sogar mit reinterpret_cast ran. Das ist die Art und Weise des Compilers, zu sagen, dass du da Mist baust. Der Compiler drück sich nämlich sehr direkt aus, nicht so subtil sarkastisch wie ich.
Ich weiß jetzt nicht so recht, ob du uns nur verarschen willst oder wirklich so naiv bist.
-
Nicht, das ich das Vorgehen verteidigen will, aber gemeint war wohl eher sowas:
Wegen dem Alignment zeigt ein Pointer auf was gerades.
Zeigt er auf etwas ungerades, dann kann man daraus schliessen, dass da ein Bit per Hand gesetzt wurde.So hab ich das verstanden. Also machbar aber schwachsinn.
-
Jockelx schrieb:
Wegen dem Alignment zeigt ein Pointer auf was gerades.
Hö? Das kommt wohl auf den Wert des alignemnts an. Was is mit #pragma pack(1)?
-
Allgemein wird das nicht funktionieren, aber das wird er wohl auch nicht vorhaben.
-
Wenn der Platzmangel so groß ist, dass man schon Bits irgendwo reinschustern muss könnte ich mir gut vorstellen, dass auch das Alignment auf 1 gesetzt wurde um Platz zu sparen

-
IMHO sind Pointer auf
Linux/Windows, 32/64 bit, gerade. Stimmt das immer (und warum)?definitiv nicht.
Es gibt zwar meist ein 4 byte alignment, das verhindert aber nicht ungerade Pointer.
Einfaches beispiel zum nachvollziehen:
const char testchar[] = "Test";void * p1 = &testchar[0]; p1 wird wohl nicht nur gradzahlig sein
void * p2 = &testchar[1]; Preisfrage: ist p2 auch gradzahlig ???Ergo: so richtig sicher kannst du Dir nie sein, ob ein ungerader pointer nur durch manipulation zustande kam oder ob er wirklich auf das zeigt auf was er wirklich zeigen soll.
Ganz lustig wird dann sicher, wenn man den speicher ned selber allokiert, sondern allokatoren ans werk laesst. Wer garantiert, das die auch alignment verwenden ? (hoechstwahrscheinlich werden sie es, aber 100% garantiert isses sicher ned)
Ciao ...
-
Jockelx schrieb:
Nicht, das ich das Vorgehen verteidigen will, aber gemeint war wohl eher sowas:
Wegen dem Alignment zeigt ein Pointer auf was gerades.
Zeigt er auf etwas ungerades, dann kann man daraus schliessen, dass da ein Bit per Hand gesetzt wurde.So hab ich das verstanden. Also machbar aber schwachsinn.
Ja, so ist das gemeint. Die Frage war, ob das sicher ist, was bei Geradzahligkeit
gegeben sein sollte. Schwachsinn, warum?
-
Wirklich saubere Lösung gibts da eigentlich nur eine: statt eines Pointers nen Index in ein Array verwenden. Dann kann man selbst kontrollieren wie gross der Index maximal werden kann, und alle unbenutzten Bits für etwas anderes verwenden.
(Muss natürlich nicht ein Index in ein flaches Array sein, gibt ja noch Maps und B-Bäume und was nicht noch alles)
Alles andere ist ein mehr oder weniger schlimmer Hack.
p.S.: wenn der Typ auf den so ein Zeiger zeigt halbwegs gross ist, dann hat man sehr gute Chancen dass alignof(T) grösser 1 ist, und eine Zweierpotenz (also gerade). Wenn man dann nirgends pfuscht, heisst das auch, dass alle Zeiger die auf so einen Typ zeigen einen geraden Wert haben.
Ich würde es allerdings nicht machen wollen. Der Trick ist alt und wurde oft eingesetzt, und viele sind damit früher oder später auf die Schnauze gefallen. Wäre mir einfach zu riskant.
-
Schwachsinn, warum?
- gefaehrlich
- sehr ungewoehnlich, selbst wenns funktioniert. Damit überraschender / unüblicher Code -> schwer wartbar.und für was ?
Auf welchen System hat man so speichernot ? wenn ich mir anschaue was allein durchs Alignment verschenkt werden kann, dann waeren 8 statt 4 byte pro Pointer nur ein relativ geringes Übel
Dann waer vielleicht ne Option, nen 16bit compiler rauszukramen und das prog als "small" zu compilieren, dann haben pointer nur 2 byte verbrauch. Nachteil, man müsste extra ne 16bit runtime für starten
Oder den rechner mit dieser speichernot ned eh nur im realmode unter Dos/irgendwa anderes mit 16bit laufen lassen
Ne GUI bei dem speichermangel ist doch eh nen no go 
Ciao ...
-
RHBaum schrieb:
void * p1 = &testchar[0]; p1 wird wohl nicht nur gradzahlig sein
void * p2 = &testchar[1]; Preisfrage: ist p2 auch gradzahlig ???Hat mit der Frage nichts zu tun.
geom schrieb:
Schwachsinn, warum?
Wurde doch schon beantwortet. Oder nochmal gefragt:
Warum hast du unter Linux und Windows zu wenig Speicherplatz, um auf sowas zurückgreifen zu müssen?
-
(Erstmal sorry, den Originalpost habe ich als Unregistrierter gemacht. Hatte
die Userdaten nicht gleich bei der Hand..)Es handelt sich um eine Datenstruktur, die aus kleinen Objekten, die Pointer
enthalten, gebildet wird. Für diese Objekte wird ein Zustand benötigt. Da
nahezu der ganze Speicherbedarf sich auf diese kleinen Objekte bezieht - je
nach Datensatz können das mehrere GB sein - wäre ein Overhead dort gleich
dem Overhead des gesamten Speicherbedarfs.Lösung 1: Verwende ein Set. Das kostet Zeit.
Lösung 2: Verwende einen bool im Objekt. Das kostet durch das Alignment
mehrere Bytes statt einem einzigen Bit.
Lösung 3: Mache einen der Pointer ungerade, um den Zustand als gesetzt zu
markieren. Häßlich.Jede Lösung weist Nachteile auf. Da nur ein kurzer Abschnitt des Algorithmus
betroffen ist, scheint mir die Häßlichkeit von Lösung drei akzeptabel, sofern
die Möglichkeit, das _sicher_ zu machen, gegeben ist.lg
-
geom schrieb:
Lösung 1: Verwende ein Set. Das kostet Zeit.
Und das umbiegen und rumcasten von Zeigern kostet keine Zeit?
-
Falls deine Objekte z.B. in einem Array liegen und sich deren Indizes nicht oder nachvollziehbar ändern könntest du parallel dazu eine bitlist mit deinen Zuständen anlegen.
-
Etwa so?
template <typename T> class hellPtr { T* ptr_; public: hellPtr():ptr_(0){}; hellPtr(T* ptr):ptr_(ptr){}; T* operator ->(){return (T*)((unsigned int)ptr_ & 0xFFFFFFFE);}; T& operator *(){return *((T*)((unsigned int)ptr_ & 0xFFFFFFFE));}; void operator=(T* ptr){ptr_=ptr;}; operator T*(){return (T*)((unsigned int)ptr_ & 0xFFFFFFFE);}; bool getflag(){return (bool)((unsigned int)ptr_ & 1L);}; void setflag(bool b){if(b) ptr_=(T*)((unsigned int)ptr_ | 1L); else ptr_=(T*)((unsigned int)ptr_ & 0xFFFFFFFE);}; };Ist jetzt hart für 32 Bit, funktioniert aber (soweit meine Tests gingen).
Ich würde aber auch eher abraten...
~Lecker! - Braten
~
-
Caligulaminus schrieb:
Etwa so?
template <typename T> class hellPtr { T* ptr_; public: hellPtr():ptr_(0){}; hellPtr(T* ptr):ptr_(ptr){}; T* operator ->(){return (T*)((unsigned int)ptr_ & 0xFFFFFFFE);}; T& operator *(){return *((T*)((unsigned int)ptr_ & 0xFFFFFFFE));}; void operator=(T* ptr){ptr_=ptr;}; operator T*(){return (T*)((unsigned int)ptr_ & 0xFFFFFFFE);}; bool getflag(){return (bool)((unsigned int)ptr_ & 1L);}; void setflag(bool b){if(b) ptr_=(T*)((unsigned int)ptr_ | 1L); else ptr_=(T*)((unsigned int)ptr_ & 0xFFFFFFFE);}; };Ist jetzt hart für 32 Bit, funktioniert aber (soweit meine Tests gingen).
Ich würde aber auch eher abraten...
~Lecker! - Braten
~Oh, ein Smart-Pointer aus der Hölle
Gute Idee.Ich habe gerade die Alternativen getestet: Die Lösung mit dem bool, der
Speicher kostet, braucht 5.1s. Eine Lösung mit einem STL set braucht 70s,
und ein unordered_set etwa gleich lange. Indexlösungen schätze ich wegen
der indirekten Adressierung etwas teurer als die Lösung mit dem bool, das
wäre noch zu testen.lg
-
Wieso gerade std::set?
Kannst du nicht std::vector verwenden?
Statt Zeigern einfach Indexe speichern, und alle Objekte in den Vektor stopfen. Könnte leicht sein dass dadurch sogar alles schneller wird und auch weniger RAM braucht.Vielleicht beschreibst du mal genauer was das für ne Datenstruktur ist (also vom logischen her, nicht wie du es jetzt genau umgesetzt hast). Sonst können wir auch nur raten.
-
Jockelx schrieb:
Wegen dem Alignment zeigt ein Pointer auf was gerades.
Zeigt er auf etwas ungerades, dann kann man daraus schliessen, dass da ein Bit per Hand gesetzt wurde.So hab ich das verstanden. Also machbar aber schwachsinn.
Das funktioniert und höre ich nicht zum ersten mal.
Setzt natürlich viele Annahmen voraus, die man checken sollte, wenn ein neues Objekt erzeugt wird.
Prinzipiell gilt: Macht es genauso, obfuscated den Code noch und ihr habt euern Job sicher.
