当调零一个结构,如SOCKADDR_IN,并sockaddr_in6的使用addrinfo中之前,这是正确的:memset的,一个初始化或任? [英] When zeroing a struct such as sockaddr_in, sockaddr_in6 and addrinfo before use, which is correct: memset, an initializer or either?

查看:392
本文介绍了当调零一个结构,如SOCKADDR_IN,并sockaddr_in6的使用addrinfo中之前,这是正确的:memset的,一个初始化或任?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

每当我看到真正的code或书籍,手册页和网站例如插座code,我几乎总是看到这样的:

Whenever I look at real code or example socket code in books, man pages and websites, I almost always see something like:

struct sockaddr_in foo;
memset(&foo, 0, sizeof foo); 
/* or bzero(), which POSIX marks as LEGACY, and is not in standard C */
foo.sin_port = htons(42);

而不是:

struct sockaddr_in foo = { 0 }; 
/* if at least one member is initialized, all others are set to
   zero (as though they had static storage duration) as per 
   ISO/IEC 9899:1999 6.7.8 Initialization */ 
foo.sin_port = htons(42);

struct sockaddr_in foo = { .sin_port = htons(42) }; /* New in C99 */

static struct sockaddr_in foo; 
/* static storage duration will also behave as if 
   all members are explicitly assigned 0 */
foo.sin_port = htons(42);

同样也可以找到传递它的getaddrinfo,例如之前的struct addrinfo中的提示设置为零。

The same can also be found for setting struct addrinfo hints to zero before passing it to getaddrinfo, for example.

这是为什么?据我了解,不使用memset的例子可能是相当于做了一个,如果不是更好。我认识到,有差异:

Why is this? As far as I understand, the examples that do not use memset are likely to be the equivalent to the one that does, if not better. I realize that there are differences:


  • memset的将所有位设置为零,这不一定是正确的比特重presentation每个成员设置为0。

  • 的memset还将设置填充比特为零。

这些结构设置为零,所以用一个初始反而是错误的,当要么这些差异相关或所需的行为?如果是这样,为什么,以及标准或其他来源证实这一点?

Are either of these differences relevant or required behavior when setting these structs to zero and therefore using an initializer instead is wrong? If so, why, and which standard or other source verifies this?

如果都是正确的,为什么memset的/ bzero倾向于出现,而不是一个初始化?难道仅仅是风格问题?如果是这样,那很好,我不认为我们需要一个主观的答案上,这是更好的风格。

If both are correct, why does memset/bzero tend to appear instead of an initializer? Is it just a matter of style? If so, that's fine, I don't think we need a subjective answer on which is better style.

平常的做法是使用一个初始化$ p中$ pference到pcisely memset的$ P $,因为所有位零通常不希望的,而是我们要零无误再presentation用于类型(多个)。是相反的真正为这些插座相关的结构?

The usual practice is to use an initializer in preference to memset precisely because all bits zero is not usually desired and instead we want the correct representation of zero for the type(s). Is the opposite true for these socket related structs?

在我的研究,我发现,只有POSIX似乎需要sockaddr_in6的(而不是SOCKADDR_IN)的<一个被清零href=\"http://www.opengroup.org/onlinepubs/000095399/basedefs/netinet/in.h.html\">http://www.opengroup.org/onlinepubs/000095399/basedefs/netinet/in.h.html但并没有提及应该如何归零(memset的或初始化?)。我知道BSD套接字preDATE POSIX,这是不是唯一的标准,所以他们的兼容性注意事项遗留系统或现代非POSIX系统?

In my research I found that POSIX only seems to require sockaddr_in6 (and not sockaddr_in) to be zeroed at http://www.opengroup.org/onlinepubs/000095399/basedefs/netinet/in.h.html but makes no mention of how it should be zeroed (memset or initializer?). I realise BSD sockets predate POSIX and it is not the only standard, so are their compatibility considerations for legacy systems or modern non-POSIX systems?

我个人preFER从样式(也许是很好的做法)的视图中使用的初始化函数和完全避免memset的观点,但我不愿意,因为:

Personally, I prefer from a style (and perhaps good practice) point of view to use an initializer and avoid memset entirely, but I am reluctant because:


  • 其他来源$ C ​​$ c和半经典文本如 UNIX网络编程使用bzero(如页面101第二版和124页的第三版。(我自己都))。

  • 我清楚地知道,他们是不相同的,因为上述原因。

  • Other source code and semi-canonical texts like UNIX Network Programming use bzero (eg. page 101 on 2nd ed. and page 124 in 3rd ed. (I own both)).
  • I am well aware that they are not identical, for reasons stated above.

推荐答案

与部分初始化方法的一个问题(即 {0} ')是GCC将提醒你,初始化是不完整的(如果警告级别足够高,我通常使用 -Wall ,经常 -Wextra )。随着指定的初始化方法,即警告不应给予,但C99仍然没有被广泛使用 - 虽然这些部件是相当广泛的资料,但,也许,在微软的世界

One problem with the partial initializers approach (that is '{ 0 }') is that GCC will warn you that the initializer is incomplete (if the warning level is high enough; I usually use '-Wall' and often '-Wextra'). With the designated initializer approach, that warning should not be given, but C99 is still not widely used - though these parts are fairly widely available, except, perhaps, in the world of Microsoft.

往往用于青睐的方法:

static const struct sockaddr_in zero_sockaddr_in;

其次是:

struct sockaddr_in foo = zero_sockaddr_in;

在静态常量初始化的遗漏意味着一切都是零 - 但是编译器不会威特(不应惠)。分配使用编译器的先天内存拷贝除非编译器是有严重缺陷的,不会比一个函数调用速度较慢。

The omission of the initializer in the static constant means everything is zero - but the compiler won't witter (shouldn't witter). The assignment uses the compiler's innate memory copy which won't be slower than a function call unless the compiler is seriously deficient.

GCC 4.4.2版本到4.6.0生成GCC 4.7.1不同的警告。具体来说,GCC 4.7.1识别 = {0} 初始化为特殊情况,不抱怨,而GCC 4.6.0等没有抱怨。

GCC versions 4.4.2 to 4.6.0 generate different warnings from GCC 4.7.1. Specifically, GCC 4.7.1 recognizes the = { 0 } initializer as a 'special case' and doesn't complain, whereas GCC 4.6.0 etc did complain.

考虑文件 INIT.C

struct xyz
{
    int x;
    int y;
    int z;
};

struct xyz xyz0;                // No explicit initializer; no warning
struct xyz xyz1 = { 0 };        // Shorthand, recognized by 4.7.1 but not 4.6.0
struct xyz xyz2 = { 0, 0 };     // Missing an initializer; always a warning
struct xyz xyz3 = { 0, 0, 0 };  // Fully initialized; no warning

在使用GCC 4.4.2(在Mac OS X)编译的警告是:

When compiled with GCC 4.4.2 (on Mac OS X), the warnings are:

$ /usr/gcc/v4.4.2/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c init.c
init.c:9: warning: missing initializer
init.c:9: warning: (near initialization for ‘xyz1.y’)
init.c:10: warning: missing initializer
init.c:10: warning: (near initialization for ‘xyz2.z’)
$

在使用GCC 4.5.1编译的警告是:

When compiled with GCC 4.5.1, the warnings are:

$ /usr/gcc/v4.5.1/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c init.c
init.c:9:8: warning: missing initializer
init.c:9:8: warning: (near initialization for ‘xyz1.y’)
init.c:10:8: warning: missing initializer
init.c:10:8: warning: (near initialization for ‘xyz2.z’)
$

在使用GCC 4.6.0编译的警告是:

When compiled with GCC 4.6.0, the warnings are:

$ /usr/gcc/v4.6.0/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c init.c
init.c:9:8: warning: missing initializer [-Wmissing-field-initializers]
init.c:9:8: warning: (near initialization for ‘xyz1.y’) [-Wmissing-field-initializers]
init.c:10:8: warning: missing initializer [-Wmissing-field-initializers]
init.c:10:8: warning: (near initialization for ‘xyz2.z’) [-Wmissing-field-initializers]
$

在使用GCC 4.7.1编译的警告是:

When compiled with GCC 4.7.1, the warnings are:

$ /usr/gcc/v4.7.1/bin/gcc -O3 -g -std=c99 -Wall -Wextra  -c init.c
init.c:10:8: warning: missing initializer [-Wmissing-field-initializers]
init.c:10:8: warning: (near initialization for ‘xyz2.z’) [-Wmissing-field-initializers]
$

上面的编译器被我编译。苹果提供的编译器GCC名义上4.2.1和锵:

The compilers above were compiled by me. The Apple-provided compilers are nominally GCC 4.2.1 and Clang:

$ /usr/bin/clang -O3 -g -std=c99 -Wall -Wextra -c init.c
init.c:9:23: warning: missing field 'y' initializer [-Wmissing-field-initializers]
struct xyz xyz1 = { 0 };
                      ^
init.c:10:26: warning: missing field 'z' initializer [-Wmissing-field-initializers]
struct xyz xyz2 = { 0, 0 };
                         ^
2 warnings generated.
$ clang --version
Apple clang version 4.1 (tags/Apple/clang-421.11.65) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin11.4.2
Thread model: posix
$ /usr/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c init.c
init.c:9: warning: missing initializer
init.c:9: warning: (near initialization for ‘xyz1.y’)
init.c:10: warning: missing initializer
init.c:10: warning: (near initialization for ‘xyz2.z’)
$ /usr/bin/gcc --version
i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$

由于注意到 SecurityMatt 在下面留言, memset的优势()在从存储器复制的结构是,从存储器拷贝比较昂贵,需要访问两个存储单元(源和目的地),而不只是一个。通过比较,值设定为零不必访问存储器源,并在现代系统中,存储器是一个瓶颈。因此, memset的()编码应该比复制简单的初始化(其中相同的值,通常全零字节,被放置在目标存储器)更快。如果初始化是值(不是所有的零字节)的复杂组合,则余额可以支持一个初始化的改变,记法紧凑性和可靠性,如果没有别的。

As noted by SecurityMatt in a comment below, the advantage of memset() over copying a structure from memory is that the copy from memory is more expensive, requiring access to two memory locations (source and destination) instead of just one. By comparison, setting the values to zeroes doesn't have to access the memory for source, and on modern systems, the memory is a bottleneck. So, memset() coding should be faster than copy for simple initializers (where the same value, normally all zero bytes, is being placed in the target memory). If the initializers are a complex mix of values (not all zero bytes), then the balance may be changed in favour of an initializer, for notational compactness and reliability if nothing else.

有没有一个单一的分切,风干的答案... ...有可能永远是,而且现在没有。我还是倾向于使用初始化,但 memset的()往往是一个有效的替代。

There isn't a single cut and dried answer...there probably never was, and there isn't now. I still tend to use initializers, but memset() is often a valid alternative.

这篇关于当调零一个结构,如SOCKADDR_IN,并sockaddr_in6的使用addrinfo中之前,这是正确的:memset的,一个初始化或任?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆