为什么使用bzero而不是memset?

Pse*_*che 150 c memset systems-programming

在上一学期的系统编程课程中,我们必须在C中实现一个基本的客户端/服务器.初始化结构,比如sock_addr_in,或者char缓冲区(我们用来在客户端和服务器之间来回发送数据)教授指示我们只使用bzero而不是memset初始化它们.他从未解释过为什么,而且我很好奇是否有正当理由呢?

我在这里看到:http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdownbzero是更有效的,由于一个只能将要归零记忆的事实,所以也没有必须做任何额外的检查memset.尽管如此,这仍然不一定是绝对不能memset用于归零内存的理由.

bzero被认为已弃用,而且不是标准的C函数.根据手册,memset因此优先考虑bzero.所以,你为什么要仍然使用bzeromemset?只是为了提高效率,还是更多?同样,有什么好处memsetbzero,使它成为新的程序的事实上的首选?

oua*_*uah 144

我看不出有任何理由,更喜欢bzeromemset.

memset是标准的C函数,而bzero从未成为C标准函数.理由可能是因为您可以使用memset函数实现完全相同的功能.

现在关于效率,编译器就像gcc使用内置实现一样,memset0检测到常量时切换到特定实现.同为glibc当内置命令被禁用.


aus*_*tin 65

我猜你曾经使用过(或者你的老师受到了影响)W.Richard Stevens的UNIX网络编程.即使在最新版本bzeromemset,他也经常使用而不是.这本书如此受欢迎,我认为它已经成为网络编程的成语,这也是你仍然看到它被使用的原因.

我会坚持memset只是因为bzero被弃用并降低了可移植性.我怀疑你会看到使用一个而不是另一个真正的收益.

  • 实际上比这更糟糕.它在POSIX.1-2001中被弃用,在POSIX.1-2008中被删除了_removed_. (7认同)
  • 引用第三版_UNIX网络编程_的第8页,由W. Richard Stevens撰写 - _Indeed,TCPv3的作者犯了错误,在第一次打印的10次出现中交换了memset的第二和第三个参数.AC编译器无法捕获此错误,因为两次出现都是相同的...这是一个错误,并且可以使用bzero避免,因为如果使用函数原型,则将两个参数交换为bzero将始终被C编译器捕获.正如paxdiablo指出的那样,bzero已被弃用. (7认同)
  • 你是对的.我们没有这本课程的教科书,但我刚刚检查了教学大纲,_UNIX Network Programming_确实被列为可选资源.谢谢. (2认同)

Mic*_*urr 48

在一个优势,我认为bzero()有超过memset()设定存储到零的是,有一个错误的机会减少正在取得进展.

不止一次,我遇到了一个看起来像的错误:

memset(someobject, size_of_object, 0);    // clear object
Run Code Online (Sandbox Code Playgroud)

编译器不会抱怨(虽然可能会在某些编译器上启动某些警告级别),但效果将是内存未被清除.因为这不会破坏对象 - 它只是让它一个人留下 - 这个错误很可能不会显示出任何明显的东西.

bzero()不标准的事实是轻微的刺激.(FWIW,如果我的程序中的大多数函数调用都是非标准的,我不会感到惊讶;事实上,编写这样的函数是我的工作).

在另一个答案的评论中,Aaron Newton引用了以下来自Unix网络编程,第1卷,第3版,Stevens等人,第1.2节(重点补充):

bzero不是ANSI C函数.它源于早期的Berkely网络代码.尽管如此,我们在整个文本中使用它而不是ANSI C memset函数,因为bzero它比memset(使用三个参数)更容易记住(只有两个参数).几乎所有支持套接字API的供应商也提供bzero,如果没有,我们在unp.h标头中提供宏定义.

事实上,TCPv3 [TCP/IP Illustrated,第3卷 - 史蒂文斯1996]的作者犯了错误,即memset在第一次打印中将第二和第三个参数交换为10次.AC编译器无法捕获此错误,因为两个参数的类型相同.(实际上,第二个参数是a int和第三个参数size_t,通常是一个unsigned int,但是指定的值,分别为0和16,对于另一种类型的参数仍然可以接受.)调用memset仍然有效,因为只有一个很少有套接字函数实际上要求将Internet套接字地址结构的最后8个字节设置为0.然而,这是一个错误,可以通过使用来避免 bzero,因为bzero如果使用函数原型,交换两个参数将始终被C编译器捕获.

我也相信绝大多数调用memset()是零内存,那么为什么不使用针对该用例量身定制的API呢?

可能的缺点bzero()是编译器可能更有可能进行优化,memcpy()因为它是标准的,因此可能会编写它们来识别它.但是,请记住,正确的代码仍然比已经优化的错误代码更好.在大多数情况下,使用bzero()不会对程序的性能产生明显影响,并且bzero()可以是扩展为的宏或内联函数memcpy().

  • +1.那个`memset`违反了"buffer,buffer_size"的通用参数排序,使得它特别容易出错IMO. (6认同)
  • 我认为这是一个甚至可以在课堂外进行的论证 - 我在生产代码中看到了这个错误.它让我感到很容易犯错误.我还猜测绝大多数`memset()`调用只是将一块内存清零,我认为这是`bzero()`的另一个参数.无论如何,`bzero()中的'b'代表什么? (5认同)
  • @Gewure 第二个和第三个参数的顺序错误;引用的函数调用完全_什么都不做_ (3认同)

小智 5

随心所欲。:-)

\n\n
#ifndef bzero\n#define bzero(d,n) memset((d),0,(n))\n#endif\n
Run Code Online (Sandbox Code Playgroud)\n\n

注意:

\n\n
    \n
  1. 原来bzero什么也不返回,memset返回void指针( d)。这可以通过在定义中将类型转换添加到 void 来解决。
  2. \n
  3. #ifndef bzero即使原始函数存在,也不会阻止您隐藏它。它测试宏是否存在。这可能会引起很多混乱。
  4. \n
  5. 创建指向宏的函数指针是不可能的。当bzero通过函数指针使用时,这将不起作用。
  6. \n
\n

  • @Palec,后者。将重新定义隐藏为宏可能会导致很多混乱。另一位使用这段代码的程序员认为他正在使用一个东西,并且在不知不觉中被迫使用另一个东西。那是一颗定时炸弹。 (2认同)
  • 您确实应该将宏命名为“bzero”以外的名称。这是一种暴行。 (2认同)