【问题标题】:Why does stdatomic.h contain atomic_uint_least16_t and atomic_uint_fast16_t but not atomic_uint16_t?为什么 stdatomic.h 包含 atomic_uint_least16_t 和 atomic_uint_fast16_t 但不包含 atomic_uint16_t?
【发布时间】:2020-11-01 23:06:57
【问题描述】:

stdatomic.h appears to containatomic_uint_least16_tatomic_uint_fast16_t,它们是_Atomic版本的stdint.h typesuint_least16_tuint_fast16_t,但它不包含atomic_uint16_t为什么?


来自N1548 draft的一些背景信息:

7.18.1.1 精确宽度整数类型

1 typedef 名称intN_t 指定宽度为 N、无填充位和二进制补码表示的有符号整数类型。因此,int8_t 表示这样一个宽度正好为 8 位的有符号整数类型。

2 typedef 名称uintN_t 指定宽度为 N 且无填充位的无符号整数类型。因此,uint24_t 表示这样一种无符号整数类型,其宽度正好为 24 位。

3 这些类型是可选的。但是,如果实现提供整数类型 宽度为 8、16、32 或 64 位,无填充位,并且(对于有符号类型)具有 二进制补码表示,它应该定义相应的typedef名称。

7.18.1.2 最小宽度整数类型

1 typedef 名称int_leastN_t 指定宽度至少为 N 的有符号整数类型,使得没有更小尺寸的有符号整数类型至少具有指定的宽度。因此,int_least32_t 表示宽度至少为 32 位的有符号整数类型。

2 typedef 名称uint_leastN_t 指定一个宽度至少为 N 的无符号整数类型,因此没有更小尺寸的无符号整数类型至少具有指定的宽度。因此,uint_least16_t 表示一个无符号整数类型,其宽度至少为 16 位。

3 需要以下类型:

int_least8_t
int_least16_t
int_least32_t
int_least64_t
uint_least8_t
uint_least16_t
uint_least32_t
uint_least64_t

此表单的所有其他类型都是可选的。

(等等,包括int_fastN_t / uint_fastN_t 类型等)

第 3 段值得强调:

但是,如果实现提供整数类型 宽度为 8、16、32 或 64 位,无填充位,并且(对于有符号类型)具有二进制补码表示,它应定义相应的 typedef 名称。

这意味着,例如,如果我有一个像 intshort 这样的类型,它被实现为具有二进制补码表示的 16 位整数,那么实现 shall 定义 @ 987654352@.

<stdatomic.h>atomic_ 类型也在N1548 中列出(转载如下),但它没有做出相应的要求,如果实现有int16_t,那么就有atomic_int16_t ---这就是我的问题的本质。

7.17.6 原子整数和地址类型

1 对于下表中的每一行,原子类型名称声明为 对应的直接类型。

Atomic type name         Direct type
----------------         -----------
atomic_char              _Atomic char
atomic_schar             _Atomic signed char
atomic_uchar             _Atomic unsigned char
atomic_short             _Atomic short
atomic_ushort            _Atomic unsigned short
atomic_int               _Atomic int
atomic_uint              _Atomic unsigned int
atomic_long              _Atomic long
atomic_ulong             _Atomic unsigned long
atomic_llong             _Atomic long long
atomic_ullong            _Atomic unsigned long long
atomic_char16_t          _Atomic char16_t
atomic_char32_t          _Atomic char32_t
atomic_wchar_t           _Atomic wchar_t
atomic_int_least8_t      _Atomic int_least8_t
atomic_uint_least8_t     _Atomic uint_least8_t
atomic_int_least16_t     _Atomic int_least16_t
atomic_uint_least16_t    _Atomic uint_least16_t
atomic_int_least32_t     _Atomic int_least32_t
atomic_uint_least32_t    _Atomic uint_least32_t
atomic_int_least64_t     _Atomic int_least64_t
atomic_uint_least64_t    _Atomic uint_least64_t
atomic_int_fast8_t       _Atomic int_fast8_t
atomic_uint_fast8_t      _Atomic uint_fast8_t
atomic_int_fast16_t      _Atomic int_fast16_t
atomic_uint_fast16_t     _Atomic uint_fast16_t
atomic_int_fast32_t      _Atomic int_fast32_t
atomic_uint_fast32_t     _Atomic uint_fast32_t
atomic_int_fast64_t      _Atomic int_fast64_t
atomic_uint_fast64_t     _Atomic uint_fast64_t
atomic_intptr_t          _Atomic intptr_t
atomic_uintptr_t         _Atomic uintptr_t
atomic_size_t            _Atomic size_t
atomic_ptrdiff_t         _Atomic ptrdiff_t
atomic_intmax_t          _Atomic intmax_t
atomic_uintmax_t         _Atomic uintmax_t

2 对这些类型的操作的语义在 7.17.7 中定义。

3 atomic_bool 类型提供原子布尔值。

4 atomic_address 类型提供原子 void * 操作。单位 加/减应该是一个字节。

5 注意原子整数和地址类型的表示不需要与它们对应的常规类型具有相同的大小。它们应尽可能具有相同的大小,因为它可以减轻所需的工作量 移植现有代码。

【问题讨论】:

    标签: c language-lawyer c11 stdatomic stdint


    【解决方案1】:

    这个专门的原子类型列表只是因为一个历史性的事故而存在,它们旨在确保与 C++ 的兼容性。而且,它们只是为了为强制的整数类型提供接口。 uintXX_t 类型都不是强制性的,因此不包括在内。

    (通过添加atomic_[u]intprt_t 立即实现了这一目标,其中[u]intptr_t 不是强制性的,但这可能是另一个故事。)

    【讨论】:

    • 所以uint_least16_tuint_fast16_t 是必需的,但uint16_t 不是必需的?!
    • 是的,完全正确。仅当平台具有完全对应宽度的整数类型时,才需要固定宽度类型别名。
    • 我不明白为什么原子类型不反映 stdint.h 类型——例如如果需要uint32_t,为什么不atomic_uint32_t
    • (用标准草案 N1548 中的一些引文编辑了我的问题)
    • uint32_t 通常不需要,仅当平台具有正好 32 个值位且没有填充位的整数类型时。
    【解决方案2】:

    我只能猜测,但是如果您只能对大于 uint16_t 的事物实现原子访问,那么始终可以通过相应地定义类型来实现对 uint_least16_t 和 uint_fast16_t 的原子访问,而对 uint16_t 的原子访问可能是不可能的可用的硬件。而且您不希望标准中有任何无法实施的内容。

    【讨论】:

    • uint16_t 根本不保证存在。我认为这就是问题所在。 _Atomic uint16_t isn't guaranteed to have the same sizeuint16_t 一样,所以实现肯定有可能只有 32 位原子操作,但不知何故仍然有 uint16_t,并通过填充到 32 位来实现 _Atomic uint16_t。但它仅可用于提供uint16_t 的实现。所以atomic_uint16_t 可以作为可选类型提供。
    • 而且您不希望标准中有任何无法实现的内容。标准的作者可能希望避免暗示某些实现比其他实现更好,但我更愿意让标准包含某些实现无法支持的东西,而不是没有标准的方法来完成只有 99% 的目标平台才能支持的事情。
    • @supercat:幸运的是,在这种情况下,您可以在任何具有 uint16_t 的 C 实现上简单地编写 _Atomic uint16_t,例如作为typedef _Atomic uint16_t atomic_u16 的一部分。与假设的 atomic_uint16_t 相比,这没有任何缺点,除了类型的标准化名称。如有必要,将其扩展到 32 位(例如)的实现由 _Atomic 限定符提供,而不是便利的 typedef。但总的来说,100% 同意 C 可移植地公开更多常见但非通用的 CPU 功能(例如 popcount 和 bit-scan)。
    • @PeterCordes:不幸的是,标准不允许实现可能能够直接对本机类型原子地执行一些有用的操作,但不能对它们执行比较和交换.如果标准定义了可以直接在本地类型上执行原子操作的可选函数,并且分离出报告不同级别详细信息的函数,那么只需添加一个库就可以有效地升级现有实现,而无需编译器知道或关心原子类型。
    • @PeterCordes:在原始 8086 等平台或许多具有原子操作的读-修改-写指令并根据它们所做的设置标志的微控制器上,分离报告级别很重要,但是不要捕获整个旧值或新值。即使平台具有比较和交换功能,也可以处理减量,例如sub dword [esi], 1 / sbc eax,eax / ret 可能比尝试使用比较和交换循环更有效,如果代码关心的是值是否减到零以上[使用 -1 作为“空闲状态”值]。
    猜你喜欢
    • 1970-01-01
    • 2019-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-25
    • 1970-01-01
    相关资源
    最近更新 更多