位域的意外行为

2024-01-06

我编译了代码,

#include <stdio.h>

struct s {
    int a : 6;
    _Bool b : 1;
    _Bool c : 1;
    _Bool d : 1;
    _Bool e : 1;
    _Bool f : 1;
    _Bool g : 1;
    int h : 12;
};

void main(void) {
    printf("%d\n", sizeof(struct s));
}

输出有点出乎意料。

12

正如C11草案所述,

...如果剩余足够的空间,结构中紧随另一个位字段的位字段应打包到同一单元的相邻位中...

由于我使用 32 位编译器,因此我预计它可以容纳 4 个字节。具体来说,我使用了 gcc (tdm-1) 5.1.0。是否违反标准?


EDIT:

更换所有_Bools to an int按预期工作...我不知道为什么...


EDIT:

在 gcc 5.4.0 中,代码按预期工作。这个问题的关键点是为什么尾随_Bools 和int不适合第一个。我认为我没有对实现做太多假设(除了int至少 4 个字节,这是可以接受的),并且我在这里谈论的是 C 标准对 C 的保证行为。因此,我cannot同意下面的一些评论。


这些是位字段。 “预期”输出没有太多影响,因为标准对这些输出的规定非常糟糕。此外,编译器往往对它们的支持很差。

首先,您引用的完整部分(6.7.2.1/11)说:

实现可以分配任何大的可寻址存储单元 足以容纳一个位域。如果还有足够的空间,则一个位字段 紧随结构中另一个位字段之后的位字段应被打包 到同一单元的相邻位。如果剩余空间不足, 是否将不适合的位域放入下一个单元或 重叠相邻单元是实现定义的。的顺序 单元内位域的分配(高位到低位或 从低阶到高阶)是实现定义的。的对齐 可寻址存储单元未指定。

所有这些意味着您几乎无法对这些位最终如何进入内存做出任何假设。你无法知道编译器将如何安排对齐,你无法知道位的位顺序,你无法知道符号,你无法知道字节序。

至于如果int and _Bool将合并到同一个“存储单元”中......那么,他们为什么会这样做呢?它们是不兼容的类型。 C 标准没有提到当您有两个不兼容类型的相邻位字段时会发生什么 - 它对主观解释持开放态度。我怀疑会有各种类型别名问题。

因此,编译器将所有这些放在单独的“存储单元”中是完全可以的。如果您将相同类型的项目相邻放置,我希望它能够合并它们,否则引用的部分将没有任何意义。例如,我期望以下尺寸为 8:

struct s {
    int a : 6;
    int h : 12;
    _Bool b : 1;
    _Bool c : 1;
    _Bool d : 1;
    _Bool e : 1;
    _Bool f : 1;
    _Bool g : 1;
};

现在,如果您想要确定性的可移植代码,您应该做的就是将位字段扔出窗口并使用按位运算符。它们是 100% 确定性且可移植的。

假设您实际上不想要一些神秘的带符号数字字段(您的原始代码暗示了这一点),那么:

#define a UINT32_C(0xFC000000)
#define b (1u << 18)
#define c (1u << 17)
#define d (1u << 16)
#define e (1u << 15)
#define f (1u << 14)
#define g (1u << 13)
#define h UINT32_C(0x00000FFF)

typedef uint32_t special_thing;

然后设计 setter/getter 函数或宏来设置/获取此 32 位块中的数据。如果编写得当,您甚至可以使此类代码与字节序无关。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

位域的意外行为 的相关文章

随机推荐

  • 在 php.ini 中设置默认欧洲时区,但 date_default_timezone_get() 返回 'UTC'

    我已经设置了php ini文件默认时区 date timezone Europe Rome 我也重启了httpd编辑后的服务 服务httpd重新启动 但是当我打电话时date default timezone get 它返回 UTC 值 为
  • 大内存块未被垃圾收集

    在寻找应用程序中的内存泄漏时 我追查了一个我无法理解的行为 我分配了一个大内存块 但它不会被垃圾收集 从而导致 OOM 除非我在 onDestroy 中显式将引用设为 null 在此示例中 我有两个几乎相同的活动 它们相互切换 两者都有一个
  • 时间:2019-03-17 标签:c#datagridviewredcross

    我有一个数据网格视图和数据表 我使用数据表作为 datagridview 的数据源 我使用线程添加和更新数据 如下所示 如果我处理完数据 我会将其删除 但有两次大红色x在 datagridview 前面 我没查出为什么 以下是我的样本 No
  • 仪器 > 设备灰显

    我正在 iOS 设备上运行一个应用程序 但在 Instruments 中 该设备显示为灰色 这也意味着我无法附加该过程 无法使用设备上的 Instruments 启动 iOS 应用程序 https stackoverflow com que
  • 使用 UIWebView 构建 HTML5 iOS 应用程序

    我有一位客户建议我们只需创建一个 UIWebView 并将所有应用程序逻辑卸载到 HTML5 应用程序即可将 HTML5 应用程序包装为本机 iOS 应用程序 这将使我们能够拥有一个 原生 iOS 应用程序和一个适用于其他设备的优秀移动应用
  • 如何使用C#获取Sql Server 2005的列描述?

    我可以在 C 中使用 Microsoft SqlServer Management Smo Table 来获取 Sql Server 2005 数据库的表列 我已经得到了column Name 但是如何在C 中获取该列的描述 我看过链接 S
  • 如何执行Realm计数查询

    如何在 Realm 上进行计数查询 例如这是我的模型 class Dog Object dynamic var name class Person Object dynamic var name let dogs List
  • 如何从Python文件的末尾开始读取行

    我需要知道如何从 python 文件中读取行 以便我先读取最后一行 然后以这种方式继续 直到光标到达文件的开头 有任何想法吗 解决此问题的一般方法是按行反向读取文本文件 可以通过至少三种方法来解决 一般问题是 由于每行可以有不同的长度 因此
  • java mysql 统计行数

    我创建此代码是为了允许我计算表中的行数 但是 我无法返回计数的数字 并显示错误 无法从结果类型为 void 的方法返回值 有人可以告诉我我的错误在哪里吗 多谢 public void num throws Exception try Thi
  • 马根托。结帐购物车中的数量无法正常使用

    我已经安装了 Magento 1 8 0 并且在本地主机上购物车工作正常 我更改购物车中产品的数量 然后按下 更新购物车 按钮 一切正常 我把网站转移到网上 购物车数量不再起作用了 当我更改产品数量并单击按钮时 数量保持不变 如果我返回并尝
  • 使用 PKG_CHECK_MODULES 时,autoconf 生成的 Makefile 不会传递库头的标志

    我的项目依赖于一个库 更准确地说 GTK 所以我在我的项目中添加了以下配置configure ac PKG CHECK MODULES GTK gtk 2 0 AC SUBST GTK CFLAGS AC SUBST GTK LIBS My
  • 更新到 Asp.Net MVC 4 RTM 后无法加载类型 HttpControllerConfigurationAttribute

    我最初正在使用 ASP Net MVC 4 Beta 和 EF 4 3 1 开发单页应用程序 我更新了 MVC 4 和 EF 5 的所有 NuGet 包 现在 每当我调用 ApiController 或 DbDataController 时
  • 将 SKSpriteNode 添加到 SKEffectNode 时金属崩溃

    gt MTLDebugRenderCommandEncoder setScissorRect 2028 failed assertion rect x 0 rect width 1080 1080 must be lt 240 添加一个简单
  • 构建定义 null

    我使用这段代码来确定特定构建的构建定义详细信息 TfsTeamProjectCollection tpc TfsTeamProjectCollectionFactory GetTeamProjectCollection tfsUri IBu
  • 来自命令行的 PHPUnit - 显示的依赖文件列表。如何让它只显示测试脚本?

    我已经在 Windows 7 上安装了 PHPUnit 以及 PHP 和 Pear 我有一个基本的测试脚本 首先
  • 如何在此父方法中等待异步方法而不使用异步修饰符?

    我有一个想要等待的方法 但我不想引起多米诺骨牌效应 认为任何东西都可以调用这个调用方法并等待它 例如我有这样的方法 public bool Save string data int rowsAffected await UpdateData
  • 在 Visual Studio Code 中添加断点

    我一定是做了一些愚蠢的错误 因为我似乎无法在 Visual Studio Code 中添加断点 当我右键单击我的代码时 会弹出以下内容 在行号旁边左键单击也不起作用 我已阅读此处的文档https code visualstudio com
  • Android 屏幕方向,晃动手机导致应用程序崩溃

    我有搜索应用程序 它加载从网络服务检索的数据 创建应用程序时 它会显示进度对话框 一旦完成加载数据 它就会关闭进度对话框 问题是在加载时 如果我改变手机的方向 它工作正常 它会尝试再次加载活动 但如果我在加载数据时开始摇动手机 应用程序就会
  • 动画 UIStackView 排列子视图内容大小变化

    当其内在内容大小发生变化时 是否可以对排列的子视图进行动画处理 例如 假设我有一个已排列的子视图 其中包含固定到边缘的单个 UILabel 该标签有少量文字 新文本出现 比之前的文本大 标签的内在内容尺寸现在更大 我希望能够像这样制作动画
  • 位域的意外行为

    我编译了代码 include