Na zajęciach z programowania systemów, w których brałem udział w poprzednim semestrze, musieliśmy zaimplementować podstawowy klient / serwer w języku C. Podczas inicjowania struktur, takich jak sock_addr_in
lub bufory znaków (których używaliśmy do przesyłania danych między klientem a serwerem) profesor poinstruował nas, abyśmy tylko ich używali, bzero
a nie memset
inicjowali. Nigdy nie wyjaśnił dlaczego, a jestem ciekawy, czy jest ku temu ważny powód?
Widzę tutaj: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown, który bzero
jest bardziej wydajny ze względu na fakt, że zawsze będzie zerował pamięć, więc nie trzeba będzie wykonać dodatkowe czynności sprawdzające memset
. To jednak niekoniecznie wydaje się być powodem, aby absolutnie nie używać memset
do zerowania pamięci.
bzero
jest uważany za przestarzały, a ponadto nie jest standardową funkcją C. Zgodnie z instrukcją, memset
jest preferowany z bzero
tego powodu. Dlaczego więc chcesz nadal używać bzero
over memset
? Tylko ze względu na wzrost wydajności, czy może to coś więcej? Podobnie, jakie są korzyści z memset
ponad bzero
które sprawiają, że de facto korzystną opcją dla nowych programów?
źródło
memset
może być nieco mniej wydajny z powodu „trochę więcej sprawdzania”, jest zdecydowanie przypadkiem przedwczesnej optymalizacji: jakiekolwiek korzyści, które możesz zobaczyć z pominięcia jednej lub dwóch instrukcji procesora, nie są tego warte, gdy możesz zagrozić przenośności kod.bzero
jest przestarzały i to wystarczający powód, aby go nie używać.Odpowiedzi:
Nie widzę żadnego powodu, aby preferować
bzero
nadmemset
.memset
jest standardową funkcją C, chociażbzero
nigdy nie była standardową funkcją C. Powodem jest prawdopodobnie to, że dokładnie tę samą funkcjonalność można osiągnąć za pomocąmemset
funkcji.Jeśli chodzi o wydajność, kompilatory, na przykład,
gcc
używają wbudowanych implementacji, dlamemset
których przełączają się na określoną implementację po0
wykryciu stałej . To samo,glibc
gdy wbudowane są wyłączone.źródło
memset
powinno to być zawsze używane w tym przypadku, ale byłem zdezorientowany, dlaczego go nie używamy. Dziękuję za wyjaśnienie i potwierdzenie moich przemyśleń.bzero
implementacjami. W tablicach nie wyrównanych używał do przekroczenia podanej długości i wyzerowania trochę więcej bajtów. Nigdy nie miałem takiego problemu po przejściu namemset
.memset_s
które powinno być użyte, jeśli chcesz mieć pewność, że kompilator nie optymalizuje po cichu - usuwa wywołanie „wyczyszczenia” pamięci w jakimś celu związanym z bezpieczeństwem (takim jak wygaszenie obszaru pamięci zawierającego wrażliwy informacje, takie jak hasło w postaci zwykłego tekstu).Domyślam się, że użyłeś (lub twój nauczyciel był pod wpływem) programowania sieciowego UNIX autorstwa W. Richarda Stevensa. Często używa
bzero
zamiastmemset
, nawet w najbardziej aktualnym wydaniu. Książka jest tak popularna, że wydaje mi się, że stała się idiomem w programowaniu sieciowym i dlatego nadal ją używasz.Trzymałbym się
memset
po prostu dlatego, żebzero
jest przestarzały i ogranicza przenośność. Wątpię, żebyś dostrzegł jakiekolwiek korzyści z używania jednego nad drugim.źródło
Jedna zaletę, że myślę, że
bzero()
ma ponadmemset()
ustawiania pamięć do zera, jest to, że istnieje zmniejszenia możliwości pomyłek.Nieraz natrafiłem na błąd, który wyglądał tak:
Kompilator nie będzie narzekał (chociaż może w niektórych kompilatorach podniesienie niektórych poziomów ostrzegawczych), a efekt będzie taki, że pamięć nie zostanie wyczyszczona. Ponieważ nie powoduje to niszczenia obiektu - po prostu pozostawia go w spokoju - istnieje spora szansa, że błąd nie przejawi się w nic oczywistego.
Fakt, że
bzero()
nie jest to standard, jest trochę drażniący. (FWIW, nie zdziwiłbym się, gdyby większość wywołań funkcji w moich programach była niestandardowa; w rzeczywistości pisanie takich funkcji to rodzaj mojej pracy).W komentarzu do innej odpowiedzi tutaj Aaron Newton zacytował następujący fragment z Unix Network Programming, tom 1, wydanie trzecie, Stevens, et al., Sekcja 1.2 (wyróżnienie dodane):
Uważam również, że zdecydowana większość wywołań
memset()
ma zerową pamięć, więc dlaczego nie użyć interfejsu API, który jest dostosowany do tego przypadku użycia?Możliwą wadą
bzero()
jest to, że kompilatory mogą być bardziej skłonne do optymalizacji,memcpy()
ponieważ są standardowe, więc mogą zostać napisane, aby je rozpoznawać. Należy jednak pamiętać, że poprawny kod jest nadal lepszy niż nieprawidłowy kod, który został zoptymalizowany. W większości przypadków użyciebzero()
nie spowoduje zauważalnego wpływu na wydajność programu, abzero()
może to być makro lub funkcja wbudowana, która rozwija się domemcpy()
.źródło
memset()
wywołań ma na celu po prostu wyzerowanie bloku pamięci, co moim zdaniem jest kolejnym argumentem zabzero()
. Co właściwie oznacza „b”bzero()
?memset
narusza wspólną kolejność parametrów „buffer, buffer_size”, co czyni go szczególnie podatnym na błędy IMO.Chciałem wspomnieć o argumentach bzero vs. memset. Zainstaluj ltrace i porównaj co robi pod maską. W systemie Linux z libc6 (2.19-0ubuntu6.6) wykonywane wywołania są dokładnie takie same (przez
ltrace ./test123
):Powiedziano mi, że jeśli nie pracuję w głębokich trzewiach libc lub dowolnej liczbie interfejsów jądra / syscall, nie muszę się o nie martwić. Jedyne, o co powinienem się martwić, to to, że wywołanie spełnia warunek zerowania bufora. Inni wspominali o tym, który jest lepszy od drugiego, więc zatrzymam się tutaj.
źródło
memset(ptr, 0, n)
gdy zobaczą,bzero(ptr, n)
i nie mogą go przekonwertować na kod wbudowany.extern void bzero(void *, size_t); void clear(void *p, size_t n) { bzero(p, n); }
tworzy wywołaniememset
. (Dołączstddef.h
dosize_t
bez niczego innego, co mogłoby kolidować.)Prawdopodobnie nie powinieneś używać
bzero
, to właściwie nie jest standardowe C, to była rzecz POSIX.Zauważ, że słowo „było” - zostało uznane za przestarzałe w POSIX.1-2001 i usunięte w POSIX.1-2008 ze względu na memset, więc lepiej jest używać standardowej funkcji C.
źródło
bzero
nie jest jej częścią.Dla funkcji memset drugim argumentem jest an,
int
a trzecim argumentem jestsize_t
,co zwykle jest an
unsigned int
, ale jeśli wartości takie jak, odpowiednio,0 and 16
dla drugiego i trzeciego argumentu zostaną wprowadzone w niewłaściwej kolejności, jako 16 i 0, to takie wywołanie memset może nadal działać, ale nic nie da. Ponieważ liczba bajtów do zainicjowania jest określona jako0
.Takiego błędu można uniknąć używając bzero, ponieważ zamiana dwóch argumentów na bzero zawsze zostanie przechwycona przez kompilator C, jeśli używane są prototypy funkcji.
źródło
Krótko mówiąc:
memset
wymagają więcej operacji montażowychbzero
.To jest źródło: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown
źródło
Zrób to, jak chcesz. :-)
Zauważ, że:
bzero
nic nie zwraca,memset
zwraca void pointer (d
). Można to naprawić, dodając rzutowanie typu do void w definicji.#ifndef bzero
nie zapobiega ukryciu oryginalnej funkcji, nawet jeśli istnieje. Testuje istnienie makra. Może to spowodować wiele zamieszania.bzero
wskaźników funkcji to nie zadziała.źródło
bzero
wskaźników funkcji to nie zadziała.bzero
. To jest okrucieństwo.memset przyjmuje 3 parametry, bzero zajmuje 2 w pamięci ograniczone, że dodatkowy parametr zajmie 4 bajty więcej i przez większość czasu będzie używany do ustawiania wszystkiego na 0
źródło