当前位置: 首页 > 知识库问答 >
问题:

位域结构的C严格混淆现象规则

樊杰
2023-03-14

下面的getValue()成员函数是否违反了c严格别名规则?

根据该标准,我认为setValue()违反了严格的混淆现象,因为Double既不是聚合类型,也不是IEEE754_64的基类。

getValue()呢?当数据成员采用位字段形式时,它是否是一种未定义的行为,如下例所示?

我正在一个大型项目中使用类似的代码。GCC-O2和-O3输出错误值。如果我添加-fno严格的别名,问题就不存在了。此外,如果我使用memcpy而不是在getValue()中强制转换,问题就不存在了。不确定是否是GCC错误。

#include <iostream>
#include <cstring>

using namespace std;
struct IEEE754_64
{
  void setValue(double);
  unsigned long long getValue();
  // Data members
  unsigned long long d_mantissa : 52;
  long long d_exponent : 11;
  unsigned long long d_sign : 1;
};

void IEEE754_64::setValue(double d)
{
  (*this) = *reinterpret_cast<IEEE754_64*>(&d);
}

unsigned long long IEEE754_64::getValue()
{
  return * reinterpret_cast<unsigned long long *>(this);
}

int main()
{
  double b = 1.0;
  IEEE754_64 d;

  memcpy(&d, &b, sizeof(double));
  cout<<hex<<d.getValue()<<endl;

  d.setValue(1.0);
  cout<<hex<<d.getValue()<<endl;
  return 0;
}

共有1个答案

马冯浩
2023-03-14

<code>reinterpret_cast的行为

非正式地,如果那里实际上也有一个< code>T对象(当然,只有当< code>T是< code>a的子对象时才会发生,反之亦然),那么转换的结果是一个指向< code>T对象的指针。

否则,强制转换的结果是指向类型错误的< code>a的指针,读取它可能会违反严格的别名规则。

正式地,上述内容在标准中的 [expr.static.cast]/13 和 [basic.compound]/4 部分进行了解释,有关详细信息,请参阅此处。

考虑到这一点,setValue 通过类型 IEEE754_64 的左值读取双精度值,毫无疑问,这是一个严格的混叠冲突。

对于getValue的情况,我们必须了解reinterpret_cast的行为

根据[basic.compound]/4,一个对象和它的第一个非静态数据成员总是指针可相互转换的。它没有列出位域的任何例外。

但[expr.static.cast]/13的相关案文是:

否则,如果原始指针值指向一个对象a,并且有一个类型为T(忽略cv限定)的对象b可以与a进行指针互换,则结果是指向b的指针。

如果我们接受位字段是“类型为无符号long的对象”,则转换的结果是指向位字段的指针。但是标准没有定义指向位字段的指针的行为。

所以,恕我直言,解释上述文本的最佳方式是说位字段不是类型无符号long long的对象。我相信这与标准的其余部分是一致的;即使没有位字段类型的prvalue,它肯定谈论了位字段类型的glvalue。

总结;我相信reinterpret_cast的结果

 类似资料:
  • 这是一个典型的严格混叠违规示例: 但假设我们添加第二: 这段代码正确吗(不调用未定义的行为)? 标准[expr.reinterpret.cast]如下: 注意:将“指针到<code>T1</code>”类型的prvalue转换为“指针到 和<code>T2是对象类型,并且<code>T2的对齐要求不比<code>T 1 我们使用 类型的原始指针值来访问 类型。 当优化打开时,GCC和Clang都会

  • 在这些注释中,user @Deduplicator坚持认为,如果别名指针或别名指针是指向字符的指针类型(限定或非限定,有符号或无符号< code>char *),则严格的别名规则允许通过不兼容的类型进行访问。所以,他的观点基本上是 和 符合并具有定义的行为。 然而,在我看来,只有第一种形式是有效的,即当别名指针是指向char的指针时;然而,在另一个方向上却不能,即当别名指针指向不兼容的类型(而不是

  • 让我们考虑以下(简化)代码来读取二进制文件的内容: 在我看来,下面一行: 包含未定义的行为:我们正在读取类型的成员,它覆盖在对象的数组之上,并且编译器可以自由地假设对象不别名。 问题是:我的解释正确吗?如果是,可以做什么来修复此代码?如果没有,为什么这里没有UB? 注1:我理解严格别名规则的目的(允许编译器避免不必要的内存加载)。此外,我知道在这种情况下,使用<code>std::memcpy</

  • 我不知道为什么下面的代码运行得很好,没有< code>gcc错误(< code >-f strict-aliasing-Wstrict-aliasing = 1 )。 如果我遵循严格的别名规则: n1570,§6.5表达式 对象的存储值只能由具有以下类型之一的左值表达式访问: -与对象的有效类型兼容的类型, — 与对象的有效类型兼容的类型的限定版本, -与对象的有效类型对应的有符号或无符号类型的类

  • 当违反严格的混淆现象规则时,我试图掌握未定义的行为。为了理解它,我读了很多关于SO的文章。然而,还有一个问题:我并不真正理解两种类型的非法别名。cpp-参考指出: 类型混淆现象 每当尝试通过AliasedType类型的glvalue读取或修改DynamicType类型对象的存储值时,除非以下之一为真,否则行为未定义: AliasedType和DynamicType类似 AliasedType是Dy

  • 我和一位同事正试图实现一个简单的多态类层次结构。我们正在开发嵌入式系统,并且仅限于使用C编译器。我们有一个基本的设计理念,可以在没有警告的情况下编译(-Wall -Wextra -fstrict-aliasing -pedantic),并且在gcc 4.8.1下运行良好。 然而,我们有点担心别名问题,因为我们并不完全了解这何时会成为一个问题。 为了演示,我们编写了一个带有“接口”IHello和两个