零长度位域的实际使用

发布于 2024-10-05 00:36:54 字数 333 浏览 0 评论 0原文

我对 C 不太确定,但 C++ 允许长度为 0 的未命名位字段。例如:

struct X
{
    int : 0;
};
  • 问题一:您能想到什么实际用途?
  • 问题二:您知道什么实际用途(如果有) ?

编辑了ice-crime回答后的示例

编辑:好的,感谢当前的答案我现在知道理论目的了。但问题是关于实际用途的,所以它们仍然成立:)

I am not totally sure about C, but C++ allows unnamed bit-fields of 0 length. For example:

struct X
{
    int : 0;
};
  • Question one: What practical uses of this can you think of?
  • Question two: What real-world practical uses (if any) are you aware of?

Edited the example after ice-crime's answer

Edit: OK, thanks to the current answers I now know the theoretical purpose. But the questions are about practical uses so they still hold :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

时光无声 2024-10-12 00:36:54

您使用零长度位字段作为一种黑客方法,让编译器布局一个结构以满足某些外部要求,无论是另一个编译器还是体系结构的布局概念(跨平台数据结构,例如二进制文件格式) )或位级标准的要求(网络数据包或指令操作码)。

一个真实的例子是 NeXT 将 xnu 内核从 Motorola 68000 (m68k) 架构移植到 i386 架构。 NeXT 有一个可用的 m68k 版本的内核。当他们将其移植到 i386 时,他们发现 i386 的对齐要求与 m68k 的不同,m68k 机器和 i386 机器在 NeXT 供应商特定的 BOOTP 结构的布局上不一致。为了使 i386 结构布局与 m68k 一致,他们添加了一个长度为零的未命名位字段,以强制 NV1 结构/nv_U 联合进行 16 位对齐。

以下是 Mac OS X 10.6.5 xnu 源代码中的相关部分:

/* from xnu/bsd/netinet/bootp.h */
/*
 * Bootstrap Protocol (BOOTP).  RFC 951.
 */
/*
 * HISTORY
 *
 * 14 May 1992 ? at NeXT
 *  Added correct padding to struct nextvend.  This is
 *  needed for the i386 due to alignment differences wrt
 *  the m68k.  Also adjusted the size of the array fields
 *  because the NeXT vendor area was overflowing the bootp
 *  packet.
 */
/* . . . */
struct nextvend {
  u_char nv_magic[4]; /* Magic number for vendor specificity */
  u_char nv_version;  /* NeXT protocol version */
  /*
   * Round the beginning
   * of the union to a 16
   * bit boundary due to
   * struct/union alignment
   * on the m68k.
   */
  unsigned short  :0;
  union {
    u_char NV0[58];
    struct {
      u_char NV1_opcode;  /* opcode - Version 1 */
      u_char NV1_xid; /* transcation id */
      u_char NV1_text[NVMAXTEXT]; /* text */
      u_char NV1_null;  /* null terminator */
    } NV1;
  } nv_U;
};

You use a zero-length bitfield as a hacky way to get your compiler to lay out a structure to match some external requirement, be it another compiler's or architecture's notion of the layout (cross-platform data structures, such as in a binary file format) or a bit-level standard's requirements (network packets or instruction opcodes).

A real-world example is when NeXT ported the xnu kernel from the Motorola 68000 (m68k) architecture to the i386 architecture. NeXT had a working m68k version of their kernel. When they ported it to i386, they found that the i386's alignment requirements differed from the m68k's in such a way that an m68k machine and an i386 machine did not agree on the layout of the NeXT vendor-specific BOOTP structure. In order to make the i386 structure layout agree with the m68k, they added an unnamed bitfield of length zero to force the NV1 structure/nv_U union to be 16-bit aligned.

Here are the relevant parts from the Mac OS X 10.6.5 xnu source code:

/* from xnu/bsd/netinet/bootp.h */
/*
 * Bootstrap Protocol (BOOTP).  RFC 951.
 */
/*
 * HISTORY
 *
 * 14 May 1992 ? at NeXT
 *  Added correct padding to struct nextvend.  This is
 *  needed for the i386 due to alignment differences wrt
 *  the m68k.  Also adjusted the size of the array fields
 *  because the NeXT vendor area was overflowing the bootp
 *  packet.
 */
/* . . . */
struct nextvend {
  u_char nv_magic[4]; /* Magic number for vendor specificity */
  u_char nv_version;  /* NeXT protocol version */
  /*
   * Round the beginning
   * of the union to a 16
   * bit boundary due to
   * struct/union alignment
   * on the m68k.
   */
  unsigned short  :0;
  union {
    u_char NV0[58];
    struct {
      u_char NV1_opcode;  /* opcode - Version 1 */
      u_char NV1_xid; /* transcation id */
      u_char NV1_text[NVMAXTEXT]; /* text */
      u_char NV1_null;  /* null terminator */
    } NV1;
  } nv_U;
};
安稳善良 2024-10-12 00:36:54

标准 (9.6/2) 仅允许 0 长度位字段作为特殊情况

作为一个特例,一个未命名的
宽度为零的位域
指定下一个的对齐方式
分配单元的位域
边界。 仅当声明
未命名的位域可能是
常量表达式是一个等于值
为零

尽管我从未在实际代码中遇到过它,但此引用中描述了唯一的用途。


作为记录,我刚刚在 VS 2010 下尝试了以下代码:

struct X {
    int i : 3, j : 5;
};

struct Y {
    int i : 3, : 0, j : 5; // nice syntax huh ?
};

int main()
{
    std::cout << sizeof(X) << " - " << sizeof(Y) << std::endl;
}

我机器上的输出确实是:4 - 8

The standard (9.6/2) only allows 0 length bit-fields as a special case :

As a special case, an unnamed
bit-field with a width of zero
specifies alignment of the next
bit-field at an allocation unit
boundary. Only when declaring an
unnamed bit-field may the
constant-expression be a value equal
to zero
.

The only use is described in this quote, although I've never encountered it in practical code yet.


For the record, I just tried the following code under VS 2010 :

struct X {
    int i : 3, j : 5;
};

struct Y {
    int i : 3, : 0, j : 5; // nice syntax huh ?
};

int main()
{
    std::cout << sizeof(X) << " - " << sizeof(Y) << std::endl;
}

The output on my machine is indeed : 4 - 8.

冰魂雪魄 2024-10-12 00:36:54
struct X { int : 0; };

是 C 中未定义的行为。

参见(强调我的):

(C99, 6.7.2.1p2) “结构或联合说明符中结构声明列表的存在声明了翻译单元内的新类型。结构声明列表是一系列结构或联合成员的声明如果 struct-declaration-list 不包含命名成员,则行为未定义

(C11 具有相同的措辞。)

您可以使用带有 0 宽度,但如果结构中没有其他命名成员,则不会。

例如:

struct W { int a:1; int :0; };  // OK
struct X { int :0; };           // Undefined Behavior

顺便说一句,对于第二个声明,gcc 使用 -pedantic 发出诊断(C 标准不要求)。

另一方面:

 struct X { int :0; };

在 GNU C 中定义。例如,Linux 内核 (include/linux/bug.h) 使用它来在条件为 true 时使用以下宏强制编译错误:

#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
struct X { int : 0; };

is undefined behavior in C.

See (emphasis mine):

(C99, 6.7.2.1p2) "The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit. The struct-declaration-list is a sequence of declarations for the members of the structure or union. If the struct-declaration-list contains no named members, the behavior is undefined"

(C11 has the same wording.)

You can use an unnamed bit-field with 0 width but not if there is no other named member in the structure.

For example:

struct W { int a:1; int :0; };  // OK
struct X { int :0; };           // Undefined Behavior

By the way for the second declaration, gcc issues a diagnostic (not required by the C Standard) with -pedantic.

On the other hand:

 struct X { int :0; };

is defined in GNU C. It is used for example by the Linux kernel (include/linux/bug.h) to force a compilation error using the following macro if the condition is true:

#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
倒带 2024-10-12 00:36:54

这是来自 MSDN 的,没有标记为 Microsoft Specific,所以我猜这是常见的 C++ 标准:

宽度为 0 的未命名位字段强制下一个位字段与下一个类型边界对齐,其中类型是成员的类型。

This is from MSDN and not marked as Microsoft Specific, so I guess this is common C++ standard:

An unnamed bit field of width 0 forces alignment of the next bit field to the next type boundary, where type is the type of the member.

独木成林 2024-10-12 00:36:54

C11 标准现在允许包含零长度位字段。这是 C 委员会草案 (N1570) 中的一个示例,我相信它说明了实际用法。

3.14内存位置
...
4. 示例结构声明为

<前><代码>结构{
字符a;
整数b:5,c:11,:0,d:8;
结构体 { int ee:8; } e;
}

包含四个单独的内存位置:成员a、位字段de.ee都是单独的内存位置,< em>并且可以同时修改,互不干扰。位字段bc一起构成了第四个存储位置。位字段 bc 不能同时修改,但例如 ba 可以.

因此,在位域 cd 之间包含零长度位域允许同时修改 bd:出色地。

The C11 standard now allows the inclusion of zero length bitfields. Here is an example from the C Committee draft (N1570), which I believe illustrates a practical usage.

3.14 memory location
...
4. EXAMPLE A structure declared as

struct {
  char a;
  int b:5, c:11, :0, d:8;
  struct { int ee:8; } e;
}

contains four separate memory locations: The member a, and bit-fields d and e.ee are each separate memory locations, and can be modified concurrently without interfering with each other. The bit-fields b and c together constitute the fourth memory location. The bit-fields b and c cannot be concurrently modified, but b and a, for example, can be.

So including the zero length bitfield in between the bitfields c and d allows the concurrent modification of b and d as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文