Gdzie sprawdzać parametry funkcji?

0

Jest przykładowo następująca funkcja kopiująca blok pamięci:

void *
copy( void *dst
, void *src
, unsigned l
){  assert(( char * )dst < ( char * )src || ( char * )dst >= ( char * )src + l );
    char *dst_c = dst, *src_c = src;
    for( unsigned i = 0; i != l; l++ )
    {   *dst_c = *src_c;
        dst_c++;
        src_c++;
    }
    return dst_c;
}

Jednak może być ona wywołana copy( dst, dst, l );. Wtedy zacznie kopiować niepotrzebnie ten sam blok na ten sam blok.
Gdzie sprawdzać, czy wykonywać to kopiowanie:

  • przed wywołaniem funkcji
if( src != dst )
    copy( dst, src, l );
  • w funkcji
void *
copy( void *dst
, void *src
, unsigned l
){  assert(( char * )dst < ( char * )src || ( char * )dst >= ( char * )src + l );
    if( src == dst )
        return dst + l;
    char *dst_c = dst, *src_c = src;
    for( unsigned i = 0; i != l; l++ )
    {   *dst_c = *src_c;
        dst_c++;
        src_c++;
    }
    return dst_c;
}

?

A może jeszcze w jakiś inny sposób?
Chodzi mi o takie rozwiązanie, które nie tylko bedzie poprawne, lecz nie będzie spowalniać programu przy zagnieżdżaniu takich funkcji, ale też wygodne dla pisania programu.
Są dwa rodzaje parametrów: te nieakceptowalne, sprawdzane powyżej instrukcją assert i te dopuszczalne, ale puste w wykonaniu.

1

Jeśli masz taką asercję, to warunek src == dst może zajść tylko jeśli chcesz kopiować 0 bajtów.

1

Abstrahując od tego co ta funkcja robi to jeśli wywołujesz ją 100 razy i sprawdzanie jest poza funkcją to 100 razy musisz napisać kod sprawdzający więc wybór wydaje się oczywisty.
BTW jeśli sprawdzanie czasem było by potrzebne, a czasem nie to napisał bym dwie funkcje gdzie jedna opakowywała by drugą i dodawała sprawdzanie.
Im mniej powtarzającego się kodu tym lepiej

1

A nie lepiej dorobić drugą funkcję? valid? Kto będzie chciał to se wywoła ją przed tą właściwą.
Ja tak zawsze robię, nie wiem czy to dobrze, chętnie się dowiem.

0
KamilAdam napisał(a):

Abstrahując od tego co ta funkcja robi to jeśli wywołujesz ją 100 razy i sprawdzanie jest poza funkcją to 100 razy musisz napisać kod sprawdzający więc wybór wydaje się oczywisty.
BTW jeśli sprawdzanie czasem było by potrzebne, a czasem nie to napisał bym dwie funkcje gdzie jedna opakowywała by drugą i dodawała sprawdzanie.
Im mniej powtarzającego się kodu tym lepiej

Śmieszna rzecz jest taka, że odpowiednio sprytny kompilator może sobie lepiej radzić z kodem, który ma takie sprawdzenie, niż z takim co nie ma, gdyż wtedy np.może mieć pewność, że regiony pamięci na których są operacje na siebie nie zachodzą. Z kolei przy opakowaniu wywołania w funkcję, już tego efektu nie uzyskamy.

0
KamilAdam napisał(a):

Abstrahując od tego co ta funkcja robi to jeśli wywołujesz ją 100 razy i sprawdzanie jest poza funkcją to 100 razy musisz napisać kod sprawdzający więc wybór wydaje się oczywisty.

Chyba że funkcja jest w bibliotece dołączanej dynamicznie i jej wywołanie nie może być zoptymalizowane przez kompilator.

BTW jeśli sprawdzanie czasem było by potrzebne, a czasem nie to napisał bym dwie funkcje gdzie jedna opakowywała by drugą i dodawała sprawdzanie.
Im mniej powtarzającego się kodu tym lepiej

2

Ja bym poszedł za radą kolegów i stworzył 2 warianty: memcpy i memcpy_unsafe.

Przy czym nie do końca rozumiem sens samych ograniczeń: jeśli chcę wykonać następującą operację, to może wiem co robię?

char buf[] = "XXHello, World!";
copy(buf, buf+2, strlen(buf+2)+1);
assert(strcmp(buf, "Hello, World!") == 0);
1
kq napisał(a):

Przy czym nie do końca rozumiem sens samych ograniczeń: jeśli chcę wykonać następującą operację, to może wiem co robię?

char buf[] = "XXHello, World!";
copy(buf, buf+2, strlen(buf+2)+1);
assert(strcmp(buf, "Hello, World!") == 0);

Oczywiście, funkcja temu nie przeszkodzi.
Ale to nie przejdzie, ponieważ zanim skopiowałby, to nadpisałby sobie końcowe znaki.

char buf[] = "Hello, World!XX";
copy(buf+2, buf, strlen(buf)-2);
assert(strcmp(buf+2, "Hello, World!") == 0);

Dlatego dla takiego przypadku stosuję funkcję kopiowania od końca.

1 użytkowników online, w tym zalogowanych: 0, gości: 1