【问题标题】:What does an unnamed zero length bit-field mean in C? [duplicate]C中未命名的零长度位字段是什么意思? [复制]
【发布时间】:2018-02-05 14:22:47
【问题描述】:

我在 C 标准草案 (n1570) 中看到了以下示例:

$3.14 第 4 段:结构声明为:

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

那么,:0 是什么意思?

我知道位域是什么,但:0 没有名字,我不明白。

:0 没有任何标识符的目的是什么?

【问题讨论】:

  • 旁注:如果在位域中放置位很重要,那么您可能一开始就不应该使用位域。
  • 我不太确定....标记的欺骗是否合适?它没有在答案中突出显示这种特殊用途。
  • 我冒昧地重新打开,因为标记的欺骗可能是误导。如果有人有任何其他的欺骗,请做这个荣誉。
  • @hacks 先生,我自己重新打开了这个问题,因为它之前被标记为对同一个问题的欺骗。你不同意我的观点吗?
  • @hacks 好的,这是正确的,但我认为这个问题有不同的方面,有具体的报价。在我看来,他们不是受骗,而是相得益彰,没有冒犯的先生。

标签: c structure bit-fields


【解决方案1】:

首先,让我们看一下章节 §6.7.2.1,结构和联合说明符,P11。它说,

一个实现可以分配任何大到足以容纳位域的可寻址存储单元。 如果有足够的空间,一个位域紧跟在一个位域之后的另一个位域 结构应打包到同一单元的相邻位中。 [...]

但是,如果我们明确地想要两个连续的位域成员,它们“可能”被打包到一个单独的内存位置以驻留在单独的内存位置(即,可寻址存储单元),上面是 强制。

下一段,P12,提到,

没有声明符但只有冒号和宽度的位域声明表示 未命名的位域。126) 作为一种特殊情况,宽度为 0 的位域结构成员表示 没有进一步的位域被打包到单元中。先前的位域(如果有)已放置。

按照您的示例,这可以确保:0 周围的两个位域成员将驻留在单独的内存位置(而不是在单个可寻址存储单元内,即使有足够的内存将它们打包成一个)。这与在两个位域之间有一个非位域成员的效果类似,以强制分离内存位置。

引用 C11,第 3.14 章,NOTE 2强调我的

位域和相邻的非位域成员位于不同的内存位置。相同 适用于两个位域,如果一个在嵌套结构声明中声明而另一个不是,或者如果 两个由零长度位域声明分隔, 或者如果它们由非位域成员分隔 声明。

另外,关于用法(“为什么需要它”部分

[...] 位域 bc 不能同时存在 已修改,但例如ba 可以。


附录:

关于并发部分,来自注释 1

两个执行线程可以更新和访问不同的内存位置,而不会相互干扰 彼此。

并且,从第 §5.1.2.4/P1 章开始,

在托管实现下,一个程序可以有多个执行线程 (或线程)同时运行。 [...]

因此,根据标准,这是一个理论上可行的选择。

【讨论】:

  • 位域bc 不能同时修改,但例如ba 可以。从? C 语言本身没有“并发”的概念,位域高度依赖于实现。
  • @AndrewHenle 这是标准报价。我想我已经足够清楚地标记章节了。 :)
  • 我在open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 搜索了 C 标准副本,但没有返回结果。诡异的。关于标准中的线程的有趣评论。
  • @AndrewHenle 我在那里看到(甚至通过您的链接)....第 3.14 章,注 4。您介意重新检查吗?
  • 我找到了。也许 PDF 中的粗体文本干扰了 Firefox 的 PDF 查看器中的搜索?将标准加载到 Acrobat Reader 中,文本搜索找到引用没有任何问题。
【解决方案2】:

这是一种确保位文件不存在的方法,否则可能会合并到一个单个内存位置。

例如,假设您有一个 8 位字符,但您想确保两个 3 位字段位于不同的位置(因此可以同时修改)。为此,您可以使用:

struct xyzzy {
    int first  : 3,
               : 0,
    int second : 3;
};

您不必担心手动填充空间,例如使用junk : 5

对于语言律师,C11 3.14 memory location /3 表示(我的重点):

位域和相邻的非位域成员位于不同的内存位置。这同样适用于两个位域,如果一个在嵌套结构声明中声明而另一个没有,或者如果这两个由零长度的位域声明分隔, 或者如果它们由非位域成员声明分隔。

【讨论】:

    【解决方案3】:

    正如您之前链接的文档所解释的那样:

    位域和相邻的非位域成员位于不同的内存位置。这同样适用于两个位域,如果一个在嵌套结构声明中声明而另一个没有,或者如果这两个由零长度的位域声明分隔,或者如果它们由非位域成员声明分隔

    这是一种告诉编译器bc 可以/将在同一个内存位置,而d 必须与它们分开并且可以同时修改为b/c 的方法

    【讨论】:

    • 考虑到依赖于实现的位域,我会说没有真正的意义。如果您需要特定的位布局,IMO 最好自己屏蔽这些位。
    • @AndrewHenle - 除了多线程访问之外没有任何意义
    猜你喜欢
    • 2019-09-12
    • 2012-01-21
    • 2018-06-24
    • 2011-03-29
    • 1970-01-01
    • 1970-01-01
    • 2019-12-08
    • 2015-06-25
    相关资源
    最近更新 更多