如何测试有符号或无符号整数的最高有效位?

问题描述 投票:1回答:3

考虑到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的定义会溢出。也许我在想这个,但我很沮丧。

c integer-overflow twos-complement
3个回答
2
投票

我认为我们可以先检查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;
    }
}

3
投票

只需在没有掩码的情况下直接测试该值:

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不是整数类型(例如,如果它是floatdouble,则该代码不应编译,因为>>的操作数需要具有整数类型。因此,它仅适用于整数类型。


0
投票

您可以做的是将其强制转换为整数,该整数必须保证足够大(所以,长?),并且然后1 << ((sizeof(clock_t) * 8) - 1);进行测试。

我还将先断言sizeof(clock_t) <= sizeof(long)


0
投票

正如Kamil Cukm指出的,如果涉及带符号类型,这是错误的。仅当使用了无符号变量并且OP想要一些也可以校正有符号变量的变量时,它才适用。

您的第一个想法几乎是正确的。溢出不是MSB,而是=右侧的表达式。它隐式为int类型,由于在您的系统上sizeof(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很难一目了然。向左移动时,对有符号和无符号值的定义方式相同。

© www.soinside.com 2019 - 2024. All rights reserved.