[英]How to test the most significant bit of signed or unsigned integer?
给定一个clock_t
数据类型,它保证是某种integer,如何使用可移植的C 代码测试最高有效位的值? 也就是说,我需要这个function的定义:
bool is_msb_set(clock_t clock);
但这里有一个转折点:你不知道clock_t
的大小,也不知道它是有符号的还是无符号的(但假设“有符号”是双标)。
我的第一个想法是这样做:
const clock_t MSB = 1 << ((sizeof(clock_t) * 8) - 1);
bool is_msb_set(clock_t value) {
return value & MSB;
}
但是如果clock_t
是有符号值,则MSB 的定义会溢出。 也许我想太多了,但我很难过。
不带掩码直接测试值:
bool is_msb_set(clock_t value) {
if (value < 0) return 1;
return value >> (sizeof(clock_t) * CHAR_BIT - 1);
}
如果>>
运算符的左侧具有“有符号类型和负值,则结果值是实现定义的”,请参阅C11 6.5.7p5 。
因为我们assumed "signed" is twos-compliment
,所以我可以测试value
是否低于 0,最高有效位将始终设置为 1。 如果它不是负数,它是正数,并且clock_t
是有符号的,那么>>
是正确定义的。
如果clock_t
是无符号的,那么value < 0
将始终返回0
并且很可能应该由编译器进行优化。
如果clock_t
不是 integer 类型(例如,如果它是float
或double
),则代码不应编译,因为>>
的操作数需要具有 integer 类型。 所以它只适用于 integer 类型。
我想我们可以先检查一下clock_t
是有符号的还是无符号的,然后进行相应的处理。
bool is_msb_set(clock_t value) {
if ((clock_t)-1 < 0) {
/* clock_t is signed */
return value < 0;
} else {
/* clock_t is unsigned */
return ((value << 1) >> 1) ^ value;
}
}
您可以做的是将其转换为 integer 保证足够大(所以,长?),然后针对1 << ((sizeof(clock_t) * 8) - 1);
进行测试 .
我还将首先断言sizeof(clock_t) <= sizeof(long)
。
正如 Kamil Cukm 所指出的,如果涉及签名类型,这是错误的。 它仅适用于使用无符号变量并且 OP 也需要对有符号变量进行正确处理的情况。
你的第一个想法几乎是正确的。 溢出的不是 MSB,而是 = 右侧的表达式。 它隐含地属于 int 类型,并且由于在您的系统 sizeof(int) < sizeof(clock_t) 上,您将所有内容从临时 int 中移出并将其放在地板上。
如果你想使用你原来的方法,你应该做的就是:
const clock_t MSB = ( (clock_t) 1 ) << ((sizeof(clock_t) * 8) - 1);
如果您想仔细检查,因为我已经输入了一些“保证”代码:
#include <limits.h>
#include <stdio.h>
int main()
{
unsigned char testUChar =
((unsigned char)1) << (( sizeof( unsigned char ) * CHAR_BIT )-1);
unsigned short testUShort =
((unsigned short)1) << (( sizeof( unsigned short ) * CHAR_BIT )-1);
unsigned int testUInt =
(unsigned int)1 << (( sizeof( unsigned int ) * CHAR_BIT )-1);
unsigned long testULong =
(unsigned long)1 << (( sizeof( unsigned long ) * CHAR_BIT )-1);
unsigned long long testULongLong =
(unsigned long long)1 << (( sizeof( long long ) * CHAR_BIT )-1);
printf( "%hhx\n", testUChar );
printf( "%hx\n", testUShort );
printf( "%x\n", testUInt );
printf( "%lx\n", testULong );
printf( "%llx\n", testULongLong );
return 0;
}
如果需要,您也可以尝试对已签名类型进行此操作。 我已经这样做了,但是你想挑剔吗 %x 仅适用于无符号,使用 %d 更难一眼看出正确性。 作为左移,它对有符号和无符号值的定义方式相同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.