Waarom gebruik maken van bzero over memset?

In een systeem Programmering klasse nam ik het vorige semester, we hadden het implementeren van een standaard client/server in C. Bij het initialiseren van de structs, zoals sock_addr_in, of char buffers (die wij gebruikt om gegevens te verzenden en weer tussen client en server) de professor gaf ons opdracht om alleen gebruik te maken bzero en niet memset te initialiseren. Hij heeft nooit uitgelegd waarom, en ik ben benieuwd of er een geldige reden voor?

Zie ik hier: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown dat bzero efficiënter te wijten aan het feit dat het alleen maar gaat om het op nul zetten van het geheugen, zodat het niet hoeft te doen een extra controle dat memset kan doen. Dat maakt het nog niet per se lijkt een reden om absoluut geen gebruik van memset voor het op nul zetten van het geheugen wel.

bzero wordt beschouwd als verouderd, en bovendien is het een niet een standaard C-functie. Volgens de handleiding, memset de voorkeur boven bzero voor deze reden. Dus waarom zou u nog steeds gebruik maken van bzero over memset? Alleen voor de efficiency of is het iets meer? Ook, wat zijn de voordelen van memset over bzero die maken dat het de facto de beste keuze voor de nieuwere programma ‘ s?

  • lijkt memset is meer draagbaar
  • “Waarom gebruik bzero over memset?” – niet. Memset is standaard, bzero niet.
  • mijn vraag is waarom niet gebruik maken van calloc in dit geval?
  • bzero is een BSDism(). memset() is een ansi-c. tegenwoordig bzero() zal waarschijnlijk worden uitgevoerd als een macro. Vraag je docent om te scheren zelf en het lezen van enkele boeken. efficiëntie is een nep-argument. Een syscall of context-switch kan gemakkelijk kosten tienduizenden klok tikt, een pass over een buffer loopt op bus-snelheid. Als u wilt optimaliseren-programma ‘ s: het minimaliseren van het aantal syscalls (door het lezen/schrijven van grotere delen)
  • Het idee dat memset misschien iets minder efficiënt, omdat van “een beetje meer moeite gaan” is zeker een geval van voortijdige optimalisatie: wat is de winst die je zou kunnen zien van het achterwege laten van een CPU instructie of twee zijn niet de moeite waard wanneer je in gevaar kan brengen draagbaarheid van uw code. bzero is verouderd, en dat is genoeg reden om hem niet te gebruiken.
  • Gerelateerd: bzero() & bcopy() versus memset() & memcpy()
  • Vaak kunt u een initializer ` = {0}` in plaats, en niet een functie op alle. Dit werd makkelijker toen rond de eeuwwisseling C gestopt eigen up-front declaratie van lokale variabelen. Een aantal echt oude paperware is nog steeds diep in de vorige eeuw, dat wel.

 

9 Replies
  1. 141

    Ik zie geen reden om de voorkeur bzero over memset.

    memset is een standaard C-functie, terwijl bzero heeft nog nooit een C standaard functie. De reden is waarschijnlijk omdat je kunt bereiken precies dezelfde functionaliteit te gebruiken memset functie.

    Nu over efficiëntie, compilers zoals gcc gebruik ingebouwde implementaties voor memset die overschakelt naar een bepaalde uitvoering wanneer er een constante 0 wordt gedetecteerd. Hetzelfde voor glibc wanneer builtins zijn uitgeschakeld.

    • Bedankt. Dit is logisch. Ik was er vrij zeker van dat memset moet altijd worden gebruikt in dit geval, maar was in de war waarom waren we niet gebruikt. Bedankt voor de verduidelijking, en waarin bevestigd mijn gedachten.
    • Ik heb veel problemen met gebroken bzero implementaties. Op niet-gebonden matrices wordt gebruikt om het doorschieten van de verstrekte lengte nul en een beetje meer in bytes. Nog nooit zo een probleem na het overschakelen naar memset.
    • Vergeet niet over memset_s die moet worden gebruikt als u ervoor wilt zorgen dat de compiler niet rustig optimaliseren-weg een oproep om “scrub” geheugen voor een aantal security-gerelateerde doeleinden (zoals het leegmaken van een regio van het geheugen, die een gevoelige informatie, zoals een wachtwoord in leesbare vorm).
  2. 63

    Ik gok dat je gebruikt (of je leraar werd beïnvloed door) UNIX Network Programming door W. Richard Stevens. Hij gebruikt bzero vaak in plaats van memset, zelfs in de meest up-to-date editie. Het boek is zo populair, ik denk dat het is uitgegroeid tot een stripverhaal, in netwerk programmeren dat is waarom je nog steeds zien gebruikt.

    Ik de stok met memset simpelweg omdat bzero is niet meer in gebruik en vermindert de draagbaarheid. Ik twijfel je zou zien geen echte voordelen van het gebruik van de ene boven de andere.

    • Je zou juist. Hadden We niet nodig leerboeken voor deze cursus, maar ik controleerde de syllabus weer en UNIX Network Programming is inderdaad vermeld als een optionele bron. Bedankt.
    • Het is eigenlijk nog erger dan dat. Het werd afgeschaft in POSIX.1-2001 en verwijderd in POSIX.1-2008.
    • Citeren pagina 8 van de derde editie van de UNIX Network Programming door W. Richard Stevens – Inderdaad, de auteur van TCPv3 de fout gemaakt van het omwisselen van de tweede en derde argumenten te memset in 10 exemplaren van de eerste druk. Een C-compiler niet vangen deze fout omdat beide exemplaren zijn hetzelfde… het was een fout, en kunnen worden vermeden met behulp van bzero, omdat het omwisselen van de twee argumenten om bzero zal altijd worden opgevangen door de C-compiler als functie prototypes worden gebruikt. Echter als paxdiablo gewezen, bzero is verouderd.
    • u moet toevoegen aan Michael ‘ s antwoord omdat het bevestigt wat hij zei.
  3. 46

    Het een voordeel dat ik denk dat bzero() heeft meer dan memset() voor het instellen van het geheugen op nul is dat er een verminderde kans op een fout die wordt gemaakt.

    Meer dan een keer heb ik een bug die eruit zag:

    memset(someobject, size_of_object, 0);    //clear object

    De compiler zal niet klagen (hoewel misschien zwengelen enkele waarschuwing niveaus kunnen op sommige compilers) en het effect zal zijn dat het geheugen niet gewist. Omdat dit niet de prullenbak van het object, maar laat het staan – er is een behoorlijke kans dat het probleem misschien niet manifest in iets duidelijk.

    Het feit dat bzero() niet standaard is het een prima verblijf. (FWIW, ik zou niet verbaasd zijn als de meeste functie-oproepen in mijn programma ‘ s zijn niet standaard; in feite het schrijven van deze functies is een soort van mijn werk).

    In een reactie op een ander antwoord hier, Aaron Newton haalde de volgende Unix Network Programming, Volume 1, 3e Editie door Stevens, et al., Paragraaf 1.2 (cursivering toegevoegd):

    bzero is niet een ANSI C-functie. Het is afgeleid van de vroege Berkely
    netwerk code. Niettemin, we gebruiken in de tekst, in plaats
    van de ANSI-C memset functie, omdat bzero is makkelijker te onthouden
    (met slechts twee argumenten) dan memset (met argumenten). Bijna
    elke leverancier die het ondersteunt de sockets-API biedt ook bzero, en
    indien niet, we bieden een macro definitie in onze unp.h kop.

    Inderdaad, de auteur van TCPv3 [TCP/IP Illustrated, Volume 3 – Stevens 1996] de fout gemaakt van het omwisselen van de tweede
    en de derde argumenten te memset in 10 exemplaren in de eerste
    afdrukken
    . Een C-compiler niet vangen deze fout omdat zowel argumenten
    zijn van hetzelfde type. (Eigenlijk het tweede argument is een int en
    het derde argument is size_t, die typisch is voor een unsigned int,
    maar de opgegeven waarden, 0 en 16, respectievelijk, zijn nog steeds aanvaardbaar
    voor de andere type van argument.) De oproep om memset nog steeds gewerkt,
    omdat slechts een paar van de socket functies eigenlijk vereist dat de
    laatste 8 bytes van een Internet aansluiting adres structuur worden ingesteld op 0.
    Niettemin, het was een fout, en een die kan worden vermeden door het gebruik van
    bzero, omdat het omwisselen van de twee argumenten om bzero altijd
    gevangen door de C-compiler als functie prototypes worden gebruikt.

    Ik ben ook van mening dat de overgrote meerderheid van de gesprekken te memset() zijn aan nul geheugen, dus waarom geen gebruik maken van een API die is afgestemd op dat van een use case?

    Een mogelijk nadeel te bzero() is dat de samenstellers wellicht eerder te optimaliseren memcpy() omdat het de standaard, zodat ze kunnen worden geschreven om het te herkennen. Houd echter in gedachten dat de juiste code wordt nog steeds beter dan een onjuiste code is geoptimaliseerd. In de meeste gevallen gebruik bzero() zal niet leiden tot een merkbare impact op de prestaties van uw programma, en dat bzero() kan een macro-of inline-functie die wordt uitgebreid naar memcpy().

    • Ja, ik veronderstel dat dit misschien een redenering bij het werken in een klaslokaal zoals deze was, zodat het mogelijk minder verwarrend voor de studenten. Ik denk niet dat dit het geval was met mijn professor, echter. Hij was een zeer groot RTFM leraar. Als u had een vraag die beantwoord konden worden door de handleiding, zou hij trekt de man-pagina ‘ s op de projector in de klas en het je laten zien. Hij werd heel veel over ingraining in ieders gedachten dat de handleiding is er om gelezen te worden en de antwoorden op veel van uw vragen. Ik ben dankbaar voor deze, in tegenstelling tot sommige andere hoogleraren.
    • Ik denk dat dit een argument dat kan worden gemaakt, zelfs buiten de klas – ik heb gezien dat deze bug in de productie code. Het lijkt mij een makkelijk fout te maken. Zou ik ook denk dat de overgrote meerderheid van de memset() gesprekken zijn gewoon op nul uit een blok geheugen, waarvan ik denk dat is een ander argument voor bzero(). Wat doet de ‘b’ in bzero() voor staan, toch?
    • +1. Dat memset strijd is met een algemene parameter bestellen van “buffer, buffer_size” maakt het bijzonder foutgevoelig IMO.
    • In Pascal vermijden ze dat door te bellen met het “fillchar” en het duurt een char. De meeste C/C++ compilers zou halen dat er één opstellen. Dat maakt me afvragen waarom compilers niet zeggen “je langs een 32/64 bit pointer waar een byte wordt verwacht” en de kick die je stevig in de compiler fouten.
    • Ik denk dat de b in bzero komt van “buffer”, @MichaelBurr. Maar het kan ook “binary” of “byte”.
    • Het lijkt erop dat dit inderdaad het juiste antwoord is op de vraag.
    • wat is de bug in de memset-een voorbeeld u geleverd..? kan je dit uitleggen?
    • tweede en derde argument zijn in de verkeerde volgorde; de opgegeven functie-aanroep doet precies niets
    • dankzij @Ichthyo .. ik zag het niet voor de hand liggende!

  4. 4

    In het kort: memset vereisen meer de assemblage dan bzero.

    Dit is de bron:
    http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown

    • Ja, dat is een ding dat ik al in de OP. Ik heb eigenlijk nog gekoppeld aan exact op die pagina. Het blijkt dat lijkt niet echt veel verschil maken als gevolg van een aantal compiler optimalisaties. Voor meer details zie de aanvaarde antwoord door ouah.
    • Dit laat alleen zien dat een onzin uitvoering van memset is traag. Op MacOS X en sommige andere systemen, memset code gebruikt die is ingesteld tijdens het opstarten, afhankelijk van de processor die u gebruikt, maakt gebruik van vector registers, en voor grote maten gebruikt prefetch instructies op slimme manieren om het laatste beetje van de snelheid.
  5. 3

    Wilde nog iets zeggen over bzero vs. memset argument. Installeren ltrace en dan vergelijken met wat het doet onder de motorkap.
    Op Linux met libc6 (2.19-0ubuntu6.6), de gesprekken zelf zijn precies hetzelfde (via ltrace ./test123):

    long m[] = {0}; //generates a call to memset(0x7fffefa28238, '\0', 8)
    int* p;
    bzero(&p, 4);   //generates a call to memset(0x7fffefa28230, '\0', 4)

    Ik heb te horen gekregen dat als ik aan het werk ben in de diepe boezem van libc of een aantal van de kernel/syscall interface, ik hoef me niet te veel zorgen over.
    Ik moet zorgen dat het gesprek voldoen aan de eis van nul ‘ ing van de buffer. Anderen hebben gezegd over die ene is beter dan de andere, dus ik zal hier stoppen.

    • Dit gebeurt omdat sommige versies van GCC zal uitstoten code voor memset(ptr, 0, n) als ze zien bzero(ptr, n) en ze kan niet converteren naar een in line-code.
  6. 3

    U waarschijnlijk moet niet gebruik bzero, het is eigenlijk niet standaard C, het was een POSIX-ding.

    En let op het woord “was” – het was verouderd in POSIX.1-2001 en verwijderd in POSIX.1-2008 in aanmerking te memset dus je bent beter af met de standaard C-functie.

    • Wat bedoel je met standaard C? Bedoel je het niet in de standaard C-bibliotheek?
    • standaard C betekent dat de ISO-norm en, ja, bzero is geen deel van uit.
    • Nee, ik bedoel, ik weet niet wat je bedoelt met elke standaard. Doet ISO-norm betekenen van de standaard C bibliotheek? Dat komt met de taal? De minimale bibliotheek dat we weten dat het er zal zijn?
    • ISO is de standaarden organisatie die verantwoordelijk is voor de C-norm, de huidige is C11, en de eerdere die C99 en C89. Zij stellen de regels vast die een implementatie moet voldoen om te worden beschouwd als C. Dus ja, als de standaard zegt een implementatie moet memset, het zal er zijn voor u. Anders is het niet C.
  7. 2

    Hebben als u dat wilt. 🙂

    #ifndef bzero
    #define bzero(d,n) memset((d),0,(n))
    #endif

    Opmerking:

    1. De oorspronkelijke bzero geeft niets, memset geeft void pointer (d). Dit kan opgelost worden door het toevoegen van de typecast om te vervallen in de definitie.
    2. #ifndef bzero niet voorkomen dat u van het verbergen van de oorspronkelijke functie, zelfs als het bestaat. Het testen van het bestaan van een macro. Dit kan leiden tot veel verwarring.
    3. Het is onmogelijk om een functie aanwijzer naar een macro. Bij het gebruik van bzero via de functie pointers, zal dit niet werken.
    • Oh god.. mijn ogen..
    • Wat is het probleem met dit, @Leeor? Algemene antipathie voor macro ‘ s aan? Of je houd niet van het feit dat deze macro kan worden verward met de functie (en mogelijk zelfs verbergt het)?
    • de laatste. Het verbergen van een herdefiniëring als een macro kan leiden tot zoveel verwarring. Een andere programmeur met behulp van deze code denkt dat hij met behulp van een ding, en is onbewust gedwongen gebruik te maken van de andere. Dat is een tijdbom.
    • Na het geven van een andere gedachte, ga ik ermee akkoord dat deze is inderdaad een slechte oplossing. Onder andere dingen die ik vond een technische reden: Bij het gebruik van bzero via de functie pointers, zal dit niet werken.
    • U moet echt uw macro iets anders dan bzero. Dit is een gruweldaad.
  8. 1

    Voor memset functie, het tweede argument is een int en het derde argument is size_t,

    void *memset(void *s, int c, size_t n);

    dat is meestal een unsigned int, maar als de waarden zoals, 0 and 16 voor de tweede en derde argument respectievelijk zijn ingevoerd in de verkeerde volgorde als 16 en dan 0,
    een dergelijke oproep te memset kan nog steeds werken, maar doen niets. Omdat het aantal bytes te initialiseren worden opgegeven als 0.

    void bzero(void *s, size_t n)

    Deze fout kan worden vermeden door gebruik te bzero, omdat het omwisselen van de twee argumenten om bzero zal altijd worden opgevangen door de C-compiler als functie prototypes worden gebruikt.

    • Deze fout kan worden vermeden met memset als je gewoon denkt van het gesprek als ‘instellen geheugen om deze waarde voor deze grootte”, of als u een IDE-dat geeft u de prototype of zelfs als je gewoon weet wat je aan het doen bent 🙂
    • Eens, maar deze functie werd gecreëerd op het moment dat de intelligente IDEs waren niet beschikbaar voor de ondersteuning.
  9. 0

    memset duurt 3 parameters, bzero duurt 2
    in het geheugen beperkt dat extra parameter zou nemen 4 bytes en de meeste van de tijd itll gebruikt worden om alles op 0

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *