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.


  • Mod

    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_t und size_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.


Anmelden zum Antworten