【问题标题】:What are 'partially overlapping objects'?什么是“部分重叠的对象”?
【发布时间】:2011-11-09 17:00:04
【问题描述】:

我刚刚在this 线程中浏览了所有可能的未定义行为,其中之一是

分配给部分重叠对象的结果

我想知道是否有人可以给我一个“部分重叠对象”的定义以及如何创建它的代码示例?

【问题讨论】:

    标签: c++ object undefined-behavior


    【解决方案1】:

    正如其他答案中指出的那样,联合是最明显的安排方式。

    这是一个更清晰的示例,说明内置赋值运算符可能如何产生部分重叠的对象。如果不是部分重叠的对象限制,此示例将不会显示 UB。

    union Y {
        int n;
        short s;
    };
    
    void test() {
        Y y;
        y.s = 3;     // s is the active member of the union
        y.n = y.s;   // Although it is valid to read .s and then write to .x
                     // changing the active member of the union, .n and .s are
                     // not of the same type and partially overlap
    }
    

    即使是相同类型的对象,您也可能会出现部分重叠。在不向X 添加填充的实现中,考虑short 严格大于char 的示例。

    struct X {
        char c;
        short n;
    };
    
    union Y {
        X x;
        short s;
    };
    
    void test() {
        Y y;
        y.s = 3;     // s is the active member of the union
        y.x.n = y.s; // Although it is valid to read .s and then write to .x
                     // changing the active member of the union, it may be
                     // that .s and .x.n partially overlap, hence UB.
    }
    

    【讨论】:

      【解决方案2】:

      union 就是一个很好的例子。
      您可以创建具有重叠成员的内存结构。

      例如(来自 MSDN):

      union DATATYPE    // Declare union type
      {
          char   ch;
          int    i;
          long   l;
          float  f;
          double d;
      } var1;
      

      现在,如果您使用分配 char 成员,则所有其他成员都未定义。那是因为它们在同一个内存块上,而你只为它的一部分设置了一个实际值:

      DATATYPE blah;
      blah.ch = 4;
      

      如果您随后尝试访问 blah.iblah.dblah.f,它们将具有未定义的值。 (因为只有第一个字节,它是一个字符,设置了它的值)

      【讨论】:

      • 很好的例子,但要显示有问题的 UB,您的示例可能应该是:blah.ch = 4; blah.i = blah.ch; 以避免与联合可用的其他 UB 混淆。
      • 但是为什么在一些关于严格别名规则的文章中,作者说唯一将类型转换为字节到字节的方法是使用联合?
      • @osgx 如果您知道它们的大小完全相同并且可以逐字节转换,则可以这样做。在此示例中,它们的大小不同,并且不能进行字节到字节的转换
      • @osgx 如果您通过成员分配并尝试访问更大大小的另一个成员,则行为未定义。如果您分配双精度并尝试访问 char 值,则结果是明确定义的。
      【解决方案3】:

      这是指指针别名的问题,在 C++ 中是禁止的,以使编译器更容易优化。可以在this thread中找到对该问题的一个很好的解释

      【讨论】:

        【解决方案4】:

        他的意思是严格的别名规则吗?内存中的对象不应与其他类型的对象重叠。

        “严格别名是由 C(或 C++)编译器做出的一个假设,即取消引用指向不同类型对象的指针永远不会引用相同的内存位置(即相互别名。)”

        【讨论】:

          【解决方案5】:

          典型的例子是使用 memcpy:

          char *s = malloc(100);
          int i;
          for(i=0; i != 100;++i) s[i] = i; /* just populate it with some data */
          char *t = s + 10;  /* s and t may overlap since s[10+i] = t[i] */
          memcpy(t, s, 20); /* if you are copying at least 10 bytes, there is overlap and the behavior is undefined */
          

          memcpy 是未定义行为的原因是因为没有执行复制所需的算法。在这种情况下,memmove 被引入作为一种安全的替代方案。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-06-08
            • 1970-01-01
            • 2017-06-05
            • 2018-01-05
            • 1970-01-01
            • 2021-08-04
            • 2019-09-25
            • 1970-01-01
            相关资源
            最近更新 更多