Hoe omgekeerde memcmp te doen?

Hoe kan ik omgekeerde geheugenvergelijkingen uitvoeren? Net als in, geef ik de uiteinden van twee reeksen en ik wil dat de aanwijzer naar het begin wordt verlaagd, niet naar het einde toe wordt opgehoogd.

5
@VladLazarenko, hoewel dit gaat over vergelijken en niet kopiëren, ik denk dat het antwoord hetzelfde is - vandaar dat dit als een dupe kan worden beschouwd.
toegevoegd de auteur Till, de bron
Oeps, sorry, verkeerde markering
toegevoegd de auteur user405725, de bron
Ik heb eigenlijk een klein foutje gemaakt, ik neem mijn stem terug, sorry jongens
toegevoegd de auteur user405725, de bron

4 antwoord

Er is geen ingebouwde functie in de C-standaardbibliotheek om dit te doen. Hier is een eenvoudige manier om je eigen te rollen:

int memrcmp(const void *s1, const void *s2, size_t n)
{
    if(n == 0)
        return 0;

   //Grab pointers to the end and walk backwards
    const unsigned char *p1 = (const unsigned char*)s1 + n - 1;
    const unsigned char *p2 = (const unsigned char*)s2 + n - 1;

    while(n > 0)
    {
       //If the current characters differ, return an appropriately signed
       //value; otherwise, keep searching backwards
        if(*p1 != *p2)
            return *p1 - *p2;
        p1--;
        p2--;
        n--;
    }

    return 0;
}

Als u iets met hoge prestaties doet, vergelijkt u woorden van 4 bytes in plaats van afzonderlijke bytes, omdat geheugenlooppas de bottleneck is; die oplossing is echter aanzienlijk complexer en niet echt de moeite waard.

4
toegevoegd
@Oren: Oeps bedankt, goede vangst. Vast.
toegevoegd de auteur Adam Rosenfield, de bron
moet const unsigned zijn char p1 = (const unsigned char ) s1 + n - 1; const unsigned char p2 = (const unsigned char ) s2 + n - 1; overweeg bijvoorbeeld n = 1.
toegevoegd de auteur OSH, de bron

Net als in een bericht ( C memcpy in reverse ) oorspronkelijk gelinkt door Vlad Lazarenko, hier is een oplossing op basis daarvan, die ik nog niet heb getest, maar waarmee u moet beginnen.

int reverse_memcmp(const void *s1, const void *s2, size_t n)
{
    unsigned char *a, *b;
    a = s1;
    b = s2;
    size_t i = 0;

   //subtracting i from last position and comparing
    for (i = 0; i < n; i++) {
        if (a[n-1-i] != b[n-1-i]) {
           //return differences between different byte, strcmp()-style
            return (a[n-1-i] - b[n-1-i]);
        }
    }

    return 0;
}
1
toegevoegd
Dit compileert niet - void * -aanwijzers kunnen niet worden afgeleid. In plaats daarvan moet u casten naar unsigned char * voordat u de referentie definieert.
toegevoegd de auteur Adam Rosenfield, de bron
Goede vangst. Vast.
toegevoegd de auteur Dan Fego, de bron

Het enige dat u hoeft te doen, is uw twee doelen opgeven en de grootte die u wilt vergelijken, evenals een stapgrootte. Houd er rekening mee dat de stapgrootte mogelijk het belangrijkste onderdeel is om de verwachte resultaten te krijgen. Het zal de implementatie aanzienlijk vergemakkelijken als u de maten beperkt. Voor de grootte van een char zou je zoiets als kunnen doen:

int compare (void *one, void *two, size_t size)
  {
  char *one_char = (char *)one;
  char *two_char = (char *)two;
  size_t i;

  for (i = 0; i < size; i++)
    {
    if (*(one_char - i) != *(two_char - i))
       return(NOT_EQUAL);
    }  

  return(EQUAL);
  }
0
toegevoegd

kortere code (C-code heeft geen force-pointertype cast nodig):

int reverse_memcmp(const void *end1, const void *end2, size_t n) {
    const unsigned char *a = end1, *b = end2;
    for (; n; --n)
        if (*--a != *--b) return *a - *b;
    return 0;
}
0
toegevoegd