我在签名位字段上遇到了奇怪的行为:
#include <stdio.h>
struct S {
long long a31 : 31;
long long a32 : 32;
long long a33 : 33;
long long : 0;
unsigned long long b31 : 31;
unsigned long long b32 : 32;
unsigned long long b33 : 33;
};
long long f31(struct S *p) { return p->a31 + p->b31; }
long long f32(struct S *p) { return p->a32 + p->b32; }
long long f33(struct S *p) { return p->a33 + p->b33; }
int main() {
struct S s = { -2,-2,1,1 };
long long a32 = -2;
unsigned long long b32 = 1;
printf("f31(&s) => %lld\n",f31(&s));
printf("f32(&s) => %lld\n",f32(&s));
printf("f33(&s) => %lld\n",f33(&s));
printf("s.a31 + s.b31 => %lld\n",s.a31 + s.b31);
printf("s.a32 + s.b32 => %lld\n",s.a32 + s.b32);
printf("s.a33 + s.b33 => %lld\n",s.a33 + s.b33);
printf(" a32 + b32 => %lld\n",a32 + b32);
return 0;
}
在OS / X上使用Clang,我得到以下输出:
f31(&s) => -1 f32(&s) => 4294967295 f33(&s) => -1 s.a31 + s.b31 => 4294967295 s.a32 + s.b32 => 4294967295 s.a33 + s.b33 => -1 a32 + b32 => -1
在Linux上使用GCC,我得到了:
f31(&s) => -1 f32(&s) => 4294967295 f33(&s) => 8589934591 s.a31 + s.b31 => 4294967295 s.a32 + s.b32 => 4294967295 s.a33 + s.b33 => 8589934591 a32 + b32 => -1
上面的输出显示了三种不一致类型:
- 不同编译器的行为不同;
- 不同位域宽度的行为不同;
- 内联表达式和包装在函数中的等效表达式的不同行为。
C标准使用以下语言:
6.7.2类型说明符
...
每个逗号分隔的多集指定相同的类型,但对于位字段,指定符
int
指定与signed int
相同的类型还是指定与unsigned int
相同的类型,则由实现定义p=1013; g=3; h=245; G=[g]; a=[1]; b=[0]; a_found=0; def t_next(i,t): if t%3==0: G.append((G[i]*g)%p); elif t%3==1: G.append((G[i]*h)%p); else: G.append((G[i]^2)%p); def a_next(i,t): if t%3==0: a.append((a[i]+1)%p); elif t%3==1: a.append((a[i])%p); else: a.append((2*a[i])%p); def b_next(i,t): if t%3==0: b.append((b[i])%p); elif t%3==1: b.append((b[i]+1)%p); else: b.append((2*b[i])%p); i=1; c=1; while a_found != 1: n=i; for k in range(n,2*n+1): j=k-1; t_next(j,G[j]); a_next(j,G[j]); a b_next(j,G[j]); i+=1; if G[c]==G[2*c]: a_found=1; print [i,G[c],G[2*c],a[c],a[2*c],b[c],b[2*c]] else: c+=1;
。
众所周知,在许多较旧的编译器中,位字段都被破坏了...
Clang和GCC的行为是一致的还是这些不一致是一个或多个错误的结果?