C 为什么在memset上使用bzero?
在上学期我参加的一个系统编程课程中,我们必须用C语言实现一个基本的客户机/服务器。当初始化结构时,比如中的C 为什么在memset上使用bzero?,c,memset,systems-programming,C,Memset,Systems Programming,在上学期我参加的一个系统编程课程中,我们必须用C语言实现一个基本的客户机/服务器。当初始化结构时,比如中的sock\u addr\u或char缓冲区(我们用来在客户机和服务器之间来回发送数据)教授指示我们只使用bzero而不使用memset来初始化它们。他从未解释过原因,我很好奇这是否有正当的理由 我在这里看到:bzero效率更高,因为它只会对内存进行归零,所以它不需要像memset那样做任何额外的检查。不过,这仍然不一定是绝对不使用memset对内存进行调零的理由 bzero被认为是不推荐使用
sock\u addr\u或char缓冲区(我们用来在客户机和服务器之间来回发送数据)教授指示我们只使用bzero
而不使用memset
来初始化它们。他从未解释过原因,我很好奇这是否有正当的理由
我在这里看到:bzero
效率更高,因为它只会对内存进行归零,所以它不需要像memset
那样做任何额外的检查。不过,这仍然不一定是绝对不使用memset
对内存进行调零的理由
bzero
被认为是不推荐使用的,而且它不是标准的C函数。根据手册,出于这个原因,memset
优于bzero
。那么,您为什么还要在memset
上使用bzero
?只是为了提高效率,还是更多?同样地,memset
比bzero
有什么好处,使其成为较新程序事实上的首选选项?我猜您使用了W.Richard Stevens的UNIX网络编程(或者您的老师受到了影响)。他经常使用bzero
而不是memset
,即使是在最新版本中。这本书很受欢迎,我认为它已经成为网络编程中的一个习惯用语,这就是为什么你仍然看到它被使用的原因
我会坚持使用memset
,因为bzero
不受欢迎,降低了可移植性。我怀疑你会看到使用一个比另一个有什么实际好处。我看不出有任何理由更喜欢bzero
而不是memset
memset
是标准的C函数,而bzero
从来都不是C标准函数。基本原理可能是因为您可以使用memset
函数实现完全相同的功能
现在,关于效率,像gcc
这样的编译器使用memset
的内置实现,当检测到常量0
时,这些实现会切换到特定的实现。当内置被禁用时,glibc
也是如此。我认为bzero()
比memset()
设置内存为零有一个优点,那就是减少了出错的机会
我不止一次遇到这样一个bug:
memset(someobject, size_of_object, 0); // clear object
编译器不会抱怨(尽管可能会在某些编译器上启动一些警告级别),结果是内存没有被清除。因为这不会破坏对象——只会让它单独存在——所以很有可能bug不会表现为任何明显的东西
bzero()
不是标准的事实是一个轻微的刺激。(FWIW,如果我的程序中的大多数函数调用都是非标准的,我不会感到惊讶;事实上,编写这样的函数是我的工作)
在对另一个答案的评论中,Aaron Newton引用了Stevens等人出版的《Unix网络编程》第1卷第3版第1.2节(重点添加)中的以下内容:
bzero
不是ANSI C函数。它起源于早期的伯克利
网络代码。然而,我们在全文中使用它
因为bzero
更容易记住
(只有两个参数)而不是memset
(有三个参数)。几乎
每个支持sockets API的供应商还提供bzero
,以及
如果没有,我们将在unp.h
标题中提供宏定义
事实上,TCPv3[TCP/IP插图,第3卷-Stevens 1996]的作者犯了一个错误,即交换了第二个
和memset
的第三个参数,在第一个变量中出现10次
打印。C编译器无法捕获此错误,因为这两个参数
是同一类型的。(实际上,第二个参数是int
和
第三个参数是size\u t
,它通常是一个无符号int
,
但分别指定的值0和16仍然可以接受
对memset
的调用仍然有效,
因为实际上只有少数套接字函数需要
Internet套接字地址结构的最后8个字节必须设置为0。
然而,这是一个错误,可以通过使用
bzero
,因为将两个参数交换到bzero
将始终是
如果使用函数原型,C编译器会捕获
我还认为,对memset()
的绝大多数调用都是对零内存的调用,所以为什么不使用针对该用例定制的API呢
bzero()
的一个可能的缺点是编译器可能更倾向于优化memcpy()
,因为它是标准的,所以编写它们可能是为了识别它。但是,请记住,正确的代码仍然比经过优化的错误代码要好。在大多数情况下,使用bzero()
不会对程序的性能造成明显的影响,而且bzero()
可以是一个宏或内联函数,可以扩展到memcpy()
,您可能不应该使用bzero
,它实际上不是标准的C,而是POSIX
请注意单词“was”-它在POSIX.1-2001中被弃用,在POSIX.1-2008中被删除,以尊重memset,因此您最好使用标准C函数。对于memset函数,第二个参数是int
,第三个参数是size\u t
void *memset(void *s, int c, size_t n);
这通常是一个无符号int
,但是如果第二个和第三个参数的值分别为,0和16
void bzero(void *s, size_t n)
#ifndef bzero
#define bzero(d,n) memset((d),0,(n))
#endif
long m[] = {0}; // generates a call to memset(0x7fffefa28238, '\0', 8)
int* p;
bzero(&p, 4); // generates a call to memset(0x7fffefa28230, '\0', 4)