假设我的项目包含来自第三方库的标题,其中包含以下内容:
struct foo {
signed int x:4;
};
如果不假设位字段总是具有宽度4,并且不依赖于实现定义的行为,我如何确定可以存储在成员x
中的最大值?
答案 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_MAX
或INT_MIN
的问题相同:因为您无法自行确定,编译器实现必须提供这些值。 (你可以做的就是确定符号位的位置有实现定义(甚至是未定义)的行为:溢出,移位运算符)
对于位域,实现无法提供这些值,因此您将陷入困境。
这是位域实际上不应该是signed
的原因之一。位域用于位操作,没有别的,然后标志位就被浪费了。
如果您的字段为unsigned
,事情就会变得简单。您只需将-1
存储在其中,您就可以获得所有值的值,即“类型”的最大值。
答案 2 :(得分:0)
如果我这样做,我会尝试加载-1,如果它是2的补码表示,那么它将是可以存储的最大正值。 以上案例
foo.x = -1; unsigned int max_size =(unsigned int)(foo.x);
一半是无符号最大值,一半+ 1是有符号最大值