c++ 下面的代码格式是否良好,特别是关于别名规则的代码?

z6psavjg  于 2023-02-20  发布在  其他
关注(0)|答案(2)|浏览(128)

下面的模板函数是序列生成器的一部分。我提出了下面的基于联合的解决方案来代替手动移位,以使操作更加明确。它在所有测试的编译器上都工作得很好。Godbolt link
然而,尽管在实践中工作,我担心有别名规则被违反,这意味着它可能在未来或在其他编译器以外的GCC和CLANG。
严格按照C++标准:下面的代码格式正确吗?2是否会导致未定义的行为?

template <int BITS>
uint64_t flog2(uint64_t num) {
    constexpr uint64_t MAXNUM = (uint64_t(1) << BITS);    
    if (num < MAXNUM) return num; 
    union FP {
        double dbl;
        struct {
            uint64_t man: 52;
            uint32_t exp: 11;
            uint32_t sign: 1;
        };
        struct {
            uint64_t xman: 52-BITS;
            uint32_t xexp: 11+BITS;
            uint32_t xsgn: 1;
        };
    };
    FP fp;
    fp.dbl = num;
    fp.exp -= 1023-1+BITS;
    return fp.xexp;
}

谢谢!

ccrfmcuu

ccrfmcuu1#

首先,在ISO标准C中,该程序在语法上是病态的。匿名struct成员不是标准C(与C相反)。它们是一个扩展。在ISO标准C++中,struct必须通过该名称命名和访问。
我将在回答的其余部分忽略它,并假设您是通过这样的名称访问的。
从技术上讲,这不是别名冲突,而是在中阅读联合对象的非活动成员的未定义行为

fp.exp -= 1023-1+BITS;

类型并不重要(与别名相反)。联合体中最多只有一个活动成员,这是最后一个显式创建或用成员访问/赋值表达式编写的成员。在您的情况下,fp.dbl = num;意味着dbl是活动成员,也是唯一可以从中读取的成员。
标准中有一个例外是访问联合体的标准布局类类型成员的公共初始序列,在这种情况下,可以像访问活动成员一样访问非活动成员。但是,即使两个struct {成员也只有BITS == 0具有非空公共初始序列。
然而,在实践中,编译器通常显式支持这种类型的双关语,可能已经在允许的C兼容性中支持了。
当然,即使抛开所有这些不谈,位域的布局和所涉及类型的表示也完全是由实现定义的,您不能期望它具有通用的可移植性。

osh3o9ms

osh3o9ms2#

从不是最近写入的union成员读取是未定义的行为。
此外,bit-fields的布局是由实现定义的。
因此,从严格的C++标准的Angular 来看,这段代码既调用了未定义的行为(通过在写入dbl之后阅读exp),又依赖于实现定义的行为,假设位字段布局对应于double浮点表示(顺便说一下,这也是实现定义的)。

相关问题