为什么存储在位场中的枚举类的static_cast会更改结果?

发布于 2025-02-03 07:44:25 字数 2443 浏览 3 评论 0原文

给定一个enum类存储在一个位置:

#include <cstdint>
#include <iostream>

enum class Orientation: uint8_t
{
    NORMAL        = 0,
    CLOCKWISE     = 1,
    ANTICLOCKWISE = 2
};

inline Orientation operator+(const Orientation& lvalue, const Orientation& rvalue)
{
    switch(lvalue)
    {
        case Orientation::NORMAL:    return rvalue;
        case Orientation::CLOCKWISE:
            switch (rvalue)
            {
            case Orientation::CLOCKWISE:     return Orientation::ANTICLOCKWISE;
            case Orientation::ANTICLOCKWISE: return Orientation::NORMAL;
            case Orientation::NORMAL:        return Orientation::CLOCKWISE;
            }
            __builtin_unreachable();
        case Orientation::ANTICLOCKWISE:
            switch (rvalue)
            {
            case Orientation::CLOCKWISE:     return Orientation::NORMAL;
            case Orientation::ANTICLOCKWISE: return Orientation::CLOCKWISE;
            case Orientation::NORMAL:        return Orientation::ANTICLOCKWISE;
            }
            __builtin_unreachable();
    }
    __builtin_unreachable();
}

class Puzzle {
    private:
        Orientation or1_ : 2;
        Orientation or2_ : 2;

    public:
        Puzzle(
            const Orientation or1,
            const Orientation or2
        ) :
        or1_(or1),
        or2_(or2)
        {}

        bool checkPolarity() const
        {
            return (or1_ + or2_)
                   == Orientation::NORMAL;
        }

        bool checkPolarityWithCast() const
        {
            return (static_cast<Orientation>(or1_) + static_cast<Orientation>(or2_))
                   == Orientation::NORMAL;
        }
};

int main()
{
    Puzzle puzzle(
        Orientation::ANTICLOCKWISE,
        Orientation::CLOCKWISE
    );

    std::cout << "No cast: " << puzzle.checkPolarity() << '\n';
    std::cout << "Cast:    " << puzzle.checkPolarityWithCast() << '\n';
}

在X86-64 GCC 8.4、8.5、9.3、9.4和9.5中,输出为:

 否铸造:0
演员:1
 

但是从GCC 10来看,输出为:

 否铸造:1
演员:1
 

为什么static_cast对输出有所不同?是从G ++ 10固定的编译器中的错误吗?

godbolt

Given an enum class stored in a bit-field:

#include <cstdint>
#include <iostream>

enum class Orientation: uint8_t
{
    NORMAL        = 0,
    CLOCKWISE     = 1,
    ANTICLOCKWISE = 2
};

inline Orientation operator+(const Orientation& lvalue, const Orientation& rvalue)
{
    switch(lvalue)
    {
        case Orientation::NORMAL:    return rvalue;
        case Orientation::CLOCKWISE:
            switch (rvalue)
            {
            case Orientation::CLOCKWISE:     return Orientation::ANTICLOCKWISE;
            case Orientation::ANTICLOCKWISE: return Orientation::NORMAL;
            case Orientation::NORMAL:        return Orientation::CLOCKWISE;
            }
            __builtin_unreachable();
        case Orientation::ANTICLOCKWISE:
            switch (rvalue)
            {
            case Orientation::CLOCKWISE:     return Orientation::NORMAL;
            case Orientation::ANTICLOCKWISE: return Orientation::CLOCKWISE;
            case Orientation::NORMAL:        return Orientation::ANTICLOCKWISE;
            }
            __builtin_unreachable();
    }
    __builtin_unreachable();
}

class Puzzle {
    private:
        Orientation or1_ : 2;
        Orientation or2_ : 2;

    public:
        Puzzle(
            const Orientation or1,
            const Orientation or2
        ) :
        or1_(or1),
        or2_(or2)
        {}

        bool checkPolarity() const
        {
            return (or1_ + or2_)
                   == Orientation::NORMAL;
        }

        bool checkPolarityWithCast() const
        {
            return (static_cast<Orientation>(or1_) + static_cast<Orientation>(or2_))
                   == Orientation::NORMAL;
        }
};

int main()
{
    Puzzle puzzle(
        Orientation::ANTICLOCKWISE,
        Orientation::CLOCKWISE
    );

    std::cout << "No cast: " << puzzle.checkPolarity() << '\n';
    std::cout << "Cast:    " << puzzle.checkPolarityWithCast() << '\n';
}

In x86-64 gcc 8.4, 8.5, 9.3, 9.4 and 9.5 the output is:

No cast: 0
Cast:    1

But from gcc 10, the output is:

No cast: 1
Cast:    1

Why does the static_cast make a difference to the output? Is it a bug in the compiler that was fixed from g++ 10?

godbolt here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

深府石板幽径 2025-02-10 07:44:25

With G++8.4, the assembly code for Puzzle.checkPolarity() is:

Puzzle::checkPolarity() const:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        movzx   eax, BYTE PTR [rax]
        and     eax, 3
        mov     edx, eax
        mov     rax, QWORD PTR [rbp-8]
        movzx   eax, BYTE PTR [rax]
        shr     al, 2
        and     eax, 3
        add     eax, edx
        test    al, al
        sete    al
        pop     rbp
        ret

And, as

因为G ++ 8.4和9.3不要调用自定义操作员+。我猜他们对+进行整数促销,然后平等为false。

由y​​ksisarvinen评论

看起来确实像一个固定的错误: gcc.gc.gc.gc.org.org.org.org/bugzilla/ show_bug.cgi?id = 92859


但是,该错误报告指出:

评论5 Jason Merrill 2019-12-19 14:23:49 UTC

修复了8.4/9.3/10。

而且看来它还没有完全固定,因为它似乎仍在X86-64 GCC 8.4、8.5、9.3、9.4和9.5中被错误,但该修复程序似乎确实从版本10中使用了。

With G++8.4, the assembly code for Puzzle.checkPolarity() is:

Puzzle::checkPolarity() const:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        movzx   eax, BYTE PTR [rax]
        and     eax, 3
        mov     edx, eax
        mov     rax, QWORD PTR [rbp-8]
        movzx   eax, BYTE PTR [rax]
        shr     al, 2
        and     eax, 3
        add     eax, edx
        test    al, al
        sete    al
        pop     rbp
        ret

And, as commented by Goswin von Brederlow

Because g++ 8.4 and 9.3 don't call the custom operator+. I guess they do integer promotion for the + and then the equality is false.

As commented by Yksisarvinen

Looks like a fixed bug indeed: gcc.gnu.org/bugzilla/show_bug.cgi?id=92859


However, that bug report states:

Comment 5 Jason Merrill 2019-12-19 14:23:49 UTC

Fixed for 8.4/9.3/10.

and it appears that it has not entirely been fixed as it is still appearing to be bugged in x86-64 gcc 8.4, 8.5, 9.3, 9.4 and 9.5 but the fix does appear to have worked from version 10.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文