Зачем использовать bzero над memset?

в классе системного программирования, который я взял в этом предыдущем семестре, нам пришлось реализовать базовый клиент / сервер в C. При инициализации структур, таких как sock_addr_in, или буферы символов (которые мы использовали для передачи данных между клиентом и сервером), профессор поручил нам использовать только bzero, а не memset для их инициализации. Он никогда не объяснял, почему, и мне любопытно, есть ли веская причина для этого?

Я вижу здесь: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown это bzero более эффективно из-за того, что только когда-либо будет обнуление памяти, поэтому не нужно делать никаких дополнительных проверок, что memset может сделать. Это все еще не обязательно похоже на причину абсолютно не использовать memset для обнуления памяти.

bzero считается устаревшим и, кроме того, не является стандартной функцией C. Согласно инструкции, memset is предпочтительнее bzero по этому поводу. Так почему же вы все еще хотите использовать bzero над memset? Просто для повышения эффективности, или это что-то большее? Аналогично, каковы преимущества memset над bzero что делает его де-факто предпочтительным вариантом для новых программ?

8 ответов


Я не вижу причин предпочесть bzero над memset.

memset стандартная функция C при bzero никогда не была стандартной функцией C. Обоснование, вероятно, потому, что вы можете достичь точно такой же функциональности, используя


Я предполагаю, что вы использовали (или ваш учитель повлиял) Сетевое программирование UNIX У. Ричард Стивенс. Он использует bzero часто вместо memset, даже в самой последней версии. Книга настолько популярна, я думаю, что она стала идиомой в сетевом программировании, поэтому вы все еще видите ее использование.

Я бы придерживался memset просто так bzero устарела и снижает мобильность. Я сомневаюсь, что вы увидите какие-либо реальные выгоды от использования one over другой.


единственное преимущество, которое я думаю bzero() более memset() Настройки Память до нуля, что есть меньше шансов на ошибку.

не раз я сталкивался с ошибкой, которая выглядела так:

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

компилятор не будет жаловаться (хотя, возможно, некоторые уровни предупреждения могут быть на некоторых компиляторах), и эффект будет заключаться в том, что память не очищается. Потому что это не мусор объект - он просто оставляет его в покое - есть приличный возможно, ошибка не проявится в чем-то очевидном.

тот факт, что bzero() Не стандарт является незначительным раздражителем. (FWIW, я не удивлюсь, если большинство вызовов функций в моих программах нестандартны; на самом деле написание таких функций-это моя работа).

в комментарии к другому ответу здесь Аарон Ньютон привел следующее из сетевого программирования Unix, Том 1, 3-е издание Стивенса и др. В разделе 1.2 (Курсив мой):

bzero не функцию ANSI Си. Оно выведено от раннего Berkely сетевой код. Тем не менее, мы используем его во всем тексте, вместо этого из ANSI C


короче: memset требуется больше сборочных операций, то bzero.

Это источник: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown


Вы, наверное не стоит использовать bzero, на самом деле это не стандартный C, это была вещь POSIX.

и обратите внимание, что слово "был" - это было устаревший в POSIX.1-2001 и удалены в POSIX.1-2008 из уважения к memset, поэтому вам лучше использовать стандартную функцию C.


хотел упомянуть что-то о аргументе bzero против memset. Установите ltrace, а затем сравните, что он делает под капотом. На Linux с libc6 (2.19-0ubuntu6.6), сделанные вызовы точно такие же (через ltrace ./test123):

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

мне сказали, что если я работаю в глубокие недра libc или любое количество интерфейса ядра / syscall, мне не нужно беспокоиться о них. Все, о чем я должен беспокоиться, это то, что вызов удовлетворяет требованию нуля буфер. Другие упоминали о том, какой из них предпочтительнее другого, поэтому я остановлюсь здесь.


для функции memset вторым аргументом является int и третий аргумент size_t,

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

обычно это unsigned int, но если значения, как,0 and 16 для второго и третьего аргумента соответственно вводятся в неправильном порядке как 16 и 0 затем, такой вызов memset все еще может работать, но ничего не сделает. Потому что количество байтов для инициализации указано как 0.

void bzero(void *s, size_t n)

такой ошибки можно избежать, используя bzero, потому что замена двух аргументов на bzero всегда будет поймана компилятором C, если используются прототипы функций.


имейте это так, как вам нравится. :-)

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

внимание:

  1. оригинал bzero ничего не возвращает, memset возвращает указатель void (d). Это можно исправить, добавив typecast в void в определении.
  2. #ifndef bzero не мешает вам скрывать исходную функцию, даже если она существует. Он проверяет существование макроса. Это может вызвать много путаницы.
  3. невозможно создать указатель функции на макрос. При использовании bzero через указатели на функции, это не будет работать.