繁体   English   中英

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

[英]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 类型(例如,如果它是floatdouble ),则代码不应编译,因为>>的操作数需要具有 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM