位域的可用性

3

有很多建议不要使用位字段,而是手动进行位运算(例如:When to use bit-fields in C?),因为位字段布局是实现定义的。

这是否是实际问题?例如,对于 x86-64 的 SysV ABI,定义了位字段应如何布局,因此我认为在该平台上使用位字段即使混合使用由不同编译器生成的目标代码也不应该有问题。

其他平台上的位字段是否也被标准化了?(我主要关心 Linux(SysV ABI)、MacOS 和 CygWin。)


1
请注意,x86和x86-64上的Linux遵循SysV ABIs。 - Nate Eldredge
1
@CacahueteFrito的观点“因为没有人使用它们所以有道理”非常强烈,但是毫无意义。只需查看PIC或AVR XMEGA库即可明白。 - 0___________
3
大多数操作系统(平台)都有一个应用程序二进制接口(ABI),在该平台上的编译器将遵守该ABI。然而,如果您在不同的平台之间传输二进制数据,则无法保证在一个平台上可以处理的位域在另一个平台上可以被合理解释。据我所知,没有使用位域的系统调用。 - Jonathan Leffler
2
@Rob 我不认为这个问题是_那么_基于观点的:在C标准留下实现定义的情况下,(至少)最流行的平台是否标准化了位域? - Petr Skocik
2
我相信你说的有趣用例,尽管我没有看到过,但我不从事与硬件寄存器等接口的工作。在那个工作空间之外,我认为它们没有太大的兴趣。通常最好使用位掩码。 - Jonathan Leffler
显示剩余5条评论
2个回答

1
通常在编程中没有一个简单的答案。它总是取决于许多情况。
我认为答案取决于你计划用它们做什么。
如果你想要具有可预测行为和可读代码的特定位大小整数-是的。
struct 
{
    unsigned cnt: 3;
}three_bit_counter;

three_bit_counter.cnt++;

如果你编程使用uC - 是的

如果你想使用相同的代码并将数据“打包”到位域结构中 - 不可以。

这只是一些例子。编码时最好考虑许多选项,而不是受到“大师”意见的建议。

struct 
{
    unsigned cnt: 3;
    unsigned cnt1: 4;
}three_bit_counter;

unsigned cnt;


void inccnt(void)
{
    three_bit_counter.cnt++;

}
void inccnt1(void)
{
    three_bit_counter.cnt1++;

}

void inccntmask(void)
{
    unsigned tmp = cnt & 7;
    tmp++;
    tmp &= 7;

    cnt &= ~7;
    cnt |= tmp;

}

void inccnt1mask(void)
{
    unsigned tmp = cnt & (0b1111 << 3) >> 3;

    cnt &= ~(0b1111 << 3);
    tmp++;
    tmp &= 0b1111;
    cnt |= tmp << 3;

}

问题的第二部分缺失:标准化。 - alx - recommends codidact

1
“[...] 位域的布局是由实现定义的。”
一些方面是由实现定义的。其他方面是未指定的,例如为一个位域保留的可寻址存储单元的大小。
“这是实际上的问题吗?”
这取决于你想做什么。许多适用于结构类型更广泛的问题也适用于位域。其中,
- 像结构体一样,包含位域的结构体将被任何给定的实现一致地解释,但是 - 像结构体一样,包含位域的结构体可能会被不同的实现解释不同——可能只影响位域成员。 - 像结构体成员布局一样,实现被赋予比一些程序员认为的更大的自由度来选择位域布局。
“例如,我注意到x86-64的SysV ABI定义了如何布置位域,因此我认为即使我混合使用由不同编译器生成的目标代码,在这个平台上使用位域也不应该有问题。”
当混合使用可以依赖于产生和使用相同位域布局的代码时,使用位域不会产生互操作性问题。

使用位域对于避免依赖位域布局细节的代码而言,不会造成可移植性问题。

这些是相互冲突的问题,因为互操作性需要一致的布局,但依赖布局细节会导致可移植性问题。

位域在其他平台上是否也有类似的标准化?(我主要关心Linux(SysV ABI),MacOs和CygWin。)

一般来说,对于托管实现(包括您提到的所有示例),都会有一个平台ABI定义位域布局,用于软件在平台内的互操作性。ABI对于独立实现并不特别相关,但许多或者所有这样的实现确实会指定位域布局的完整细节。如果您关心的是是否可以链接使用不同C实现编译的具有位域的代码,并获得正确工作的程序,则答案几乎肯定是“是”。


是的。最后一句话。谢谢。(我想使用位域的主要原因是,在面向用户的配置结构体(struct ns_fn_cfg{unsigned flag1:1, flag2:1, flag3;})中,它们比要求用户或某些NS_FN_CFG_FLAG1|NS_FN_CFG_FLAG2|NS_FN_CFG_FLAG3更好用,并且它们还具有比许多不是位域的_Bool字段更好的调用方代码生成。) - Petr Skocik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接