【发布时间】:2011-06-15 15:09:24
【问题描述】:
在 C 中读取和写入整数的最高位最便携的方法是什么?
这是一个彭博采访问题。当时我没有给出最佳答案。谁能解答一下?
【问题讨论】:
-
GNU C 不是很便携...
标签: c bitwise-operators
在 C 中读取和写入整数的最高位最便携的方法是什么?
这是一个彭博采访问题。当时我没有给出最佳答案。谁能解答一下?
【问题讨论】:
标签: c bitwise-operators
#define HIGH_BIT(inttype) (((inttype)1) << (CHAR_BIT * sizeof(inttype) - 1))
示例用法:
ptrdiff_t i = 4711;
i |= HIGH_BIT(ptrdiff_t); /* set high bit */
i &= ~HIGH_BIT(ptrdiff_t); /* clear high bit */
【讨论】:
首先,请注意,如果我们谈论有符号整数,则没有可移植的方式来访问最高位;标准中根本没有定义单一的可移植表示,因此“top bit”的含义原则上可以有所不同。此外,C 不允许直接访问按位表示;您可以将 int 作为 char 缓冲区访问,但您不知道“最高位”的位置。
如果我们只关心有符号整数的非负范围,并假设该范围的大小是 2 的幂(如果不是,那么我们需要再次关心有符号表示):
#define INT_MAX_BIT (INT_MAX - (INT_MAX >> 1))
#define SET_MAX_BIT(x) (x | INT_MAX_BIT)
#define CLEAR_MAX_BIT(x) (x & ~INT_MAX_BIT)
类似的方法可以用于无符号整数,它可以用来获取真正的最高位。
【讨论】:
limits.h 中指定限制的整数类型。例如,它不适用于off_t。
_MAX 宏且不调用未定义(或实现定义)行为的高效、可移植方法...
INT_MAX 的值设置为全 1(假设对于某些 n,INT_MAX 为 2^n - 1)。右移一位会导致最高位被清除。然后从原始中减去只剩下最高位。
2**N - 1。请参阅第 6.2.6.2 节。
这是一个愚蠢的,使用:
Built-in Function: int __builtin_clz (unsigned int x)
Returns the number of leading 0-bits in x, starting at the most
significant bit position. If x is 0, the result is undefined.
第一次尝试:
int get_msb(int x) { return x ? __buildin_clz(x) == 0 : 0; }
注意:C 的一个怪癖是指定int 或unsigned int 参数的函数可以用其他类型调用而不会发出警告。但是,这可能涉及转换 - C++ 标准 4.7.2 说:
如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模 2n,其中 n 是用于表示无符号类型的位数)。 [注意:在二进制补码表示中,这种转换是概念性的,位模式没有变化(如果没有截断)。 ]
这意味着如果位模式不是二进制补码表示,则可能会更改位模式,这也会阻止此“解决方案”可靠地工作。 :-(
Chris 在下面的评论提供了一个解决方案(在此合并为一个函数而不是预处理器宏):
int get_msb(int x) { return x ? __buildin_clz(*(unsigned*)&x) == 0 : 0; }
【讨论】:
#define msb(x) __builtin_clz(*(unsigned)&x),但是你不能在文字数字上使用它。 GCC 解决方法是 #define msb(x) ({ typeof(x) _x = x; __builtin_clz(*(unsigned)&_x); })
int x 参数上方的函数中无论如何都会收到文字,然后您可以按照您的建议进行转换。我将更新上面的代码。谢谢!
union { int i; unsigned u; } u; u.i = x; return __builtin_clz(u.j); 一样。我使用了一个宏,以便它可以在签名和未签名的int 类型上工作,只为签名版本调用 UB。但无论您采用何种方式,最终都必然依赖于平台。
这个有什么问题?
int get_msb(int n){
return ((unsigned)n) >> (sizeof(unsigned) * CHAR_BIT - 1);
// or, optionally
return n < 0;
};
int set_msb(int n, int msb){
if (msb)
return ((unsigned)n) | (1ULL << (sizeof(unsigned) * CHAR_BIT - 1));
else return ((unsigned)n) & ~(1ULL << (sizeof(unsigned) * CHAR_BIT - 1));
};
它负责字节序、字节中的位数,并且也适用于 1 的补码。
【讨论】:
sizeof(X)*CHAR_BIT 假定没有填充位。
如果类型是无符号的,那就简单了:
(type)-1-(type)-1/2
对于带符号的值,我不知道。如果您找到一种方法,它将回答关于 SO 的几个未回答的问题:
C question: off_t (and other signed integer types) minimum and maximum values
Is there any way to compute the width of an integer type at compile-time?
也许是其他人。
【讨论】:
(type) 是类型转换为type。例如,您可以使用(unsigned int)-1 - (unsigned int) -1 / 2。
(unsigned)-1-(unsigned)-1/2 按预期给了我0x80000000。
~((unsigned)-1 >> 1)
(type)-1 - (type)-1 / 2... :-/.