我知道〜0 将评估最大字大小的位1(因此需要关注可移植性),但我仍然没有得到为什么((1<< N) - 1)是不鼓励的?
请分享您是否使用过第二张表格并遇到任何麻烦。
答案 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并执行(((long)1&lt;&lt; 32)-1),结果将不相同。
在这里你需要使用64代替32,64是长位的大小。
当你做((1