Pointer modulo rechnen
-
Hallo!
Für eine Hash-Funktion möchte ich die letzten paar Stellen eines Pointers in einen unsigned int legen. Das hier geht aber nicht:
unsigned adr1=p % hashTableLength;..wobei hashTableLength irgendwas kleines, 1024 oder so, ist. Weiß jemand, wie man das syntaktisch korrekt und portabel löst?
Danke, lg
-
portabel wird es so nicht, aber was spricht gegen einen index?
unsigned adr1=&p[i % hashTableLength];der compiler sollte daraus schon was optimales zaubern, was in maschinencode deiner ideee entspricht.
-
Dies hier müsste vollkommen portabel sein:
unsigned int adr1 = * reinterpret_cast<unsigned int*>(reinterpret_cast<char*>(p+1)-sizeof(adr1));edit: Wohlgemerkt dient obiger Code dazu, die letzten paar Stellen eines Pointers in einen unsigned int zu packen. Das modulo musst du noch hinzufügen.
edit2: 100% portabel ist es doch nicht, wenn ich länger darüber nachdenke: Sollte sizeof(unsigned int) > sizeof(void
sein (sehr ungewöhnlich aber möglich!) hätte man ein Problem. Könnte man natürlich noch abfangen - lohnt aber wohl den Aufwand nicht, weil rein hypothetisch. Der Code funktioniert jedenfalls für alle gängigen Pointer und Integergrößen.
-
argc schrieb:
Für eine Hash-Funktion möchte ich die letzten paar Stellen eines Pointers in einen unsigned int legen. Das hier geht aber nicht:
unsigned adr1=p % hashTableLength;..wobei hashTableLength irgendwas kleines, 1024 oder so, ist. Weiß jemand, wie man das syntaktisch korrekt und portabel löst?
Unter der Annahme, dass sizeof(unsigned long)==sizeof(void*) gilt, sollte das hier funktionieren:
unsigned adr1= reinterpret_cast<unsigned long>(p) % hashTableLength;Es gibt auch oft ein typedef für einen solchen Ganzzahtyp, uintptr_t, aber der ist noch nicht offiziell im C++ Standard zu finden.
-
Naja es gibt noch
ptrdiff_tundsize_t.
Die reichen bloss u.U. leider beide nicht auf Systemen mit segmentiertem Speicher.
Pointer -> Hash is doof^4 wenn man es wirklich 100% plattformunabhängig haben will.
(Und nocht mit Compilern ohne std::hash arbeiten muss, und auch boost::hash nicht verwenden will/kann)Wenn man sich auf "flat memory" Systeme beschränkt geht die Variante von krümelkacker.
Ansonsten könnte man noch sowas probieren:
size_t PointerToHash(void const* ptr) { size_t hash = 0; unsigned char const* p = reinterpret_cast<unsigned char const*>(&ptr); for (size_t i = 0; i < sizeof(void const*); i++) { hash *= speziell_super_wichtig_ausgesuchter_multiplikator_für_guten_hash; hash ^= p[i]; } return hash; }Das verlässt sich allerdings darauf dass die binäre Zeiger-Darstellung "Alias-frei" ist, also keine zwei unterschiedlichen Bitmuster für die selbe Adresse stehen können.
Ich weiss nicht ob das laut C++ Standard erlaubt ist, aber ich schätze eher schon.
Also auch doof.