考虑到clock_t
数据类型一定是整数,如何使用可移植的C代码测试最高有效位的值?换句话说,我需要此函数的定义:
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的定义会溢出。也许我在想这个,但我很沮丧。
我认为我们可以先检查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;
}
}
只需在没有掩码的情况下直接测试该值:
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
不是整数类型(例如,如果它是float
或double
,则该代码不应编译,因为>>
的操作数需要具有整数类型。因此,它仅适用于整数类型。
您可以做的是将其强制转换为整数,该整数必须保证足够大(所以,长?),并且然后对1 << ((sizeof(clock_t) * 8) - 1);
进行测试。
我还将先断言sizeof(clock_t) <= sizeof(long)
。
正如Kamil Cukm指出的,如果涉及带符号类型,这是错误的。仅当使用了无符号变量并且OP想要一些也可以校正有符号变量的变量时,它才适用。 您的第一个想法几乎是正确的。溢出不是MSB,而是=右侧的表达式。它隐式为int类型,由于在您的系统上sizeof(int) 如果您想使用原始方法,您要做的就是: 如果您想再次检查,因为我已经输入了一些“担保”代码: 如果需要,您也可以尝试使用已签名的类型。我已经做到了,但是您是否想挑剔%x仅适用于未签名的对象,因此使用%d很难一目了然。向左移动时,对有符号和无符号值的定义方式相同。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;
}