如何计算有符号位字段的最大支持值?

时间:2013-07-20 07:00:34

标签: c c99 bit-fields c11

假设我的项目包含来自第三方库的标题,其中包含以下内容:

struct foo {
    signed int x:4;
};

如果不假设位字段总是具有宽度4,并且不依赖于实现定义的行为,我如何确定可以存储在成员x中的最大值?

3 个答案:

答案 0 :(得分:5)

由于无法使用sizeof计算位域大小,因此可以提供帮助:

#include <stdio.h>

struct foo {
    signed int x: 4;
};

#define BIT(n) (1l << (n))
#define BIT_MASK(len) (BIT(len) - 1)

int main(void)
{
    struct foo f = {0};
    long i = 0;

    while (f.x >= 0) {
        f.x = BIT_MASK(++i);
    }
    printf("bits=%ld max=%ld\n", i, BIT_MASK(i));
    return 0;
}

左移直到f.x为负。

修改

上面的代码是实现定义的,检查一下,我认为这样可行(但你必须处理BIG ENDIAN):

#include <stdio.h>
#include <string.h>

struct foo {
    signed int x: 4;
};

#define BIT(n) (1l << (n))
#define BIT_MASK(len) (BIT(len) - 1)

int main(void)
{
    long x, i = 0;
    struct foo f;

    f.x = -1;
    memcpy(&x, &f, sizeof(f));
    while (1) {
        if (!(x & BIT(++i))) break; 
    }
    printf("bits=%ld max=%ld\n", i, BIT_MASK(i));
    return 0;
}

正如您现在所看到的,它不会超过 2 ^(n-1)-1 (适用于long

答案 1 :(得分:1)

基本上你不能。问题与确定INT_MAXINT_MIN的问题相同:因为您无法自行确定,编译器实现必须提供这些值。 (你可以做的就是确定符号位的位置有实现定义(甚至是未定义)的行为:溢出,移位运算符)

对于位域,实现无法提供这些值,因此您将陷入困境。

这是位域实际上不应该是signed的原因之一。位域用于位操作,没有别的,然后标志位就被浪费了。

如果您的字段为unsigned,事情就会变得简单。您只需将-1存储在其中,您就可以获得所有值的值,即“类型”的最大值。

答案 2 :(得分:0)

如果我这样做,我会尝试加载-1,如果它是2的补码表示,那么它将是可以存储的最大正值。 以上案例

foo.x = -1; unsigned int max_size =(unsigned int)(foo.x);

一半是无符号最大值,一半+ 1是有符号最大值