gpt4 book ai didi

c - 有符号位域的多重不一致行为

转载 作者:行者123 更新时间:2023-12-03 13:41:46 25 4
gpt4 key购买 nike

我在签名位域上遇到了一个奇怪的行为:

#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, -2, 1, 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

上面的输出显示了 3 种类型的不一致:
  • 不同编译器的不同行为;
  • 不同位域宽度的不同行为;
  • 内联表达式和封装在函数中的等效表达式的不同行为。

  • C 标准有这样的语言:

    6.7.2 Type specifiers

    ...

    Each of the comma-separated multisets designates the same type, except that for bit-fields, it is implementation-defined whether the specifier int designates the same type as signed int or the same type as unsigned int.


    众所周知,位域在许多较旧的编译器中都被破坏了……
    Clang 和 GCC 的行为是一致的还是这些不一致是一个或多个错误的结果?

    最佳答案

    请查看建议的代码,它可以按预期正常工作。
    出于实际目的,我建议,只要确保

  • 添加了兼容类型,
  • 返回正确的类型和
  • 正确的类型在 printf 语句中。

  • 就是这样。
    更多信息,另见引用文献[1]和 [2],如下。
    #include <stdio.h>

    struct S {
    long long a31 : 31;
    long long a32 : 32;
    long long a33 : 33;

    unsigned long long b31 : 31;
    unsigned long long b32 : 32;
    unsigned long long b33 : 33;
    };

    long long f31(struct S *p) { return ((long long)p->a31 + (long long)p->b31); }
    long long f32(struct S *p) { return ((long long)p->a32 + (long long)p->b32); }
    long long f33(struct S *p) { return ((long long)p->a33 + (long long)p->b33); }

    int main() {
    struct S s = { -2, -2, -2, 1, 1, 1 };
    long long a32 = -2;
    unsigned long long b32 = 1;

    printf("p->a31 => %lld\n", (long long)(s.a31));
    printf("p->a32 => %lld\n", (long long)(s.a32));
    printf("p->a33 => %lld\n", (long long)(s.a33));

    printf("p->b31 => %lld\n", (long long)(s.b31));
    printf("p->b32 => %lld\n", (long long)(s.b32));
    printf("p->b33 => %lld\n", (long long)(s.b33));


    printf("f31(&s) => %lld\n", (long long)(f31(&s)));
    printf("f32(&s) => %lld\n", (long long)(f32(&s)));
    printf("f33(&s) => %lld\n", (long long)(f33(&s)));
    printf("s.a31 + s.b31 => %lld\n", ((long long)s.a31 + (long long)s.b31));
    printf("s.a32 + s.b32 => %lld\n", ((long long)s.a32 + (long long)s.b32));
    printf("s.a33 + s.b33 => %lld\n", ((long long)s.a33 + (long long)s.b33));
    printf(" a32 + b32 => %lld\n", (long long) (a32 + b32));
    return 0;
    }

    p->a31       => -2
    p->a32 => -2
    p->a33 => -2
    p->b31 => 1
    p->b32 => 1
    p->b33 => 1
    f31(&s) => -1
    f32(&s) => -1
    f33(&s) => -1
    s.a31 + s.b31 => -1
    s.a32 + s.b32 => -1
    s.a33 + s.b33 => -1
    a32 + b32 => -1
    引用
    [1] Signed to unsigned conversion in C - is it always safe?
    [2] https://www.geeksforgeeks.org/bit-fields-c/
    “我们不能有指向位域成员的指针,因为它们可能不是从字节边界开始的。”

    关于c - 有符号位域的多重不一致行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58846584/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com