关于C中的比特掩蔽。为什么(〜(~0 <N))优于((1 <N)-1)?

时间:2011-10-05 09:51:32

标签: c bitmask

我知道〜0 将评估最大字大小的位1(因此需要关注可移植性),但我仍然没有得到为什么((1&lt;&lt; N) - 1)是不鼓励的?

请分享您是否使用过第二张表格并遇到任何麻烦。

6 个答案:

答案 0 :(得分:10)

看看以下几行:

1. printf("%X", ~(~0 << 31) );
2. printf("%X", (1 << 31) - 1 );

1编译并表现得像预期的那样。

2在表达式中提供警告整数溢出。

这是因为默认情况下1 << 31被视为已签名 int,因此1 << 31 = -2147483648是可能的最小整数。

因此,休息1会导致溢出。

答案 1 :(得分:4)

第一种形式绝对不是首选,我甚至会说它应该从不使用。在不支持负零的补码系统上,~0很可能是陷阱表示,因此在使用时会调用UB。

另一方面,1<<31也是UB,假设int是32位,因为它溢出。

如果你的意思是31为常数,0x7fffffff是编写掩码最简单,最正确的方法。如果您想要除int的符号位以外的所有符号位,INT_MAX是编写蒙版的最简单,最正确的方法。

只要您知道bitshift不会溢出,(1<<n)-1是设置最低n位的掩码的正确方法。最好使用(1ULL<<n)-1后跟强制转换或隐式转换,以免出现签名问题和转移溢出。

但无论你做什么,都不要使用带有符号整数的~运算符。如初。

答案 2 :(得分:1)

我不鼓励对签名值进行移位或补充操作只是一个坏主意。位模式应始终在无符号类型上生成(如果需要),然后转换为带符号的计数器部分。然后使用原始类型也不是一个好主意,因为通常在位模式上你应该控制你正在处理的位数。

所以我总是这样做

-UINT32_C(1)
~UINT32_C(0)

完全等效,最后只使用UINT32_MAX和Co。

仅在您没有完全换档的情况下才需要换档,例如

(UINT32_C(1) << N) - UINT32_C(1)

答案 3 :(得分:0)

我不喜欢彼此,但我看到很多错误(1<<N),其中值必须是64位但“1”是32位(整数是32位)和结果是错误的N> = 31。 1ULL而不是1将修复它。这是这种转变的一个危险。

此外,未定义CHAR_BIT * sizeof(int)或更多位置(类似于长整数(通常为64位)由CHAR_BIT * sizeof(long long)或更多位置)的整数。因此,像这样向右移动可能更安全:~0u>>(CHAR_BIT*sizeof(int)-N),但在这种情况下N不能为0.

答案 4 :(得分:0)

编辑:纠正了一个愚蠢的错误;并注意到可能存在的溢出问题。

我从未听说过一种形式比另一种更受欢迎。两种形式都在编译时进行评估。我总是使用第二种形式,我从来没有遇到任何麻烦。这两种形式都非常清楚读者。

其他答案注意到第二种形式出现溢出的可能性。

我认为他们之间几乎没有选择。

答案 5 :(得分:-2)

为什么气馁
〜0是单循环操作,因此更快 ((1&lt;首先进行移位,然后进行减法,这是一个算术运算。因此,由于减法,会消耗很多周期,因而不必要的开销。

更多
当你做((1

如果将类型转换为1并执行(((long)1&lt;&lt; 32)-1),结果将不相同。 在这里你需要使用64代替32,64是长位的大小。