C ++ 11中严格的别名规则

时间:2015-03-27 10:29:30

标签: c++11 postgis strict-aliasing

我在我的C ++ 11代码中使用了以下C结构(代码来自PostGis的liblwgeom,但这不是问题的核心)。使用g ++ - 4.8:

使用以下选项编译代码
-std=c++11 -Wall -Wextra -pedantic-errors -pedantic -Werror

我在编译(或警告)时没有收到任何错误(我应该得到吗?)

问题

在接受LWPOLY并且不修改LWGEOM*成员的函数中使用LWGEOM(实际由void *data;指出)是安全的。我知道这是穷人的继承,但这是我需要合作的。

详细

POLYGON:

typedef struct
{
        uint8_t type; /* POLYGONTYPE */
        uint8_t flags;
        GBOX *bbox;
        int32_t srid;
        int nrings;   /* how many rings we are currently storing */
        int maxrings; /* how many rings we have space for in **rings */
        POINTARRAY **rings; /* list of rings (list of points) */
}
LWPOLY; /* "light-weight polygon" */

LWGEOM:

typedef struct
{
        uint8_t type;
        uint8_t flags;
        GBOX *bbox;
        int32_t srid;
        void *data;
}
LWGEOM;

POINTARRAY:

typedef struct
{
        /* Array of POINT 2D, 3D or 4D, possibly missaligned. */
        uint8_t *serialized_pointlist;

        /* Use FLAGS_* macros to handle */
        uint8_t  flags;

        int npoints;   /* how many points we are currently storing */
        int maxpoints; /* how many points we have space for in serialized_pointlist */
}
POINTARRAY;

GBOX:

typedef struct
{
        uint8_t flags;
        double xmin;
        double xmax;
        double ymin;
        double ymax;
        double zmin;
        double zmax;
        double mmin;
        double mmax;
} GBOX;

当我做类似的事情时,我是否违反了严格的别名规则?

const LWGEOM* lwgeom;
...
const LWPOLY* lwpoly = reinterpret_cast<const LWPOLY*>(lwgeom);

我知道在PostGis类型中,专门设计为&#34;兼容&#34;但是我想通过这样做来了解我是否违反了标准。

另外,我注意到PostGis没有编译,默认情况下禁用严格别名(至少版本为2.1.5)。

解决方案

我的同事帮助我调查了它,似乎答案是否,它并没有违反严格的别名,但仅限于我们访问与LWPOLY相同类型的LWGEOMS成员并且在结构的开头连续布局。这就是为什么(引用标准):

3.10.10表示您可以通过指向&#34;聚合或联合&#34;来访问成员。

8.5.1定义聚合(C结构是聚合): 聚合是一个数组或类(第9条),没有用户提供的构造函数(12.1),没有私有或 受保护的非静态数据成员(第11条),没有基类(第10条),没有虚函数(10.3)。

9.2.19表示结构的指针与指向标准布局类的第一个成员的指针相同(C结构是标准布局)。

这是否是一种安全的代码方式是一个不同的问题。

1 个答案:

答案 0 :(得分:1)

是的,它违反了严格的别名规则。 LWGEOMLWPOLY是不相关的类型,intvoid*也是如此。因此,例如,lwgeom->data的修改可能无法通过lwpoly->nrings读取,反之亦然。

我用GCC4.9验证了这一点。我的代码如下:

#include <cinttypes>
#include <iostream>

using namespace std;

typedef struct {
        uint8_t type; /* POLYGONTYPE */
        uint8_t flags;
        int32_t srid;
        int nrings;   /* how many rings we are currently storing */
} LWPOLY; /* "light-weight polygon" */

typedef struct {
        uint8_t type;
        uint8_t flags;
        int32_t srid;
        void *data;
} LWGEOM;

void f(LWGEOM* pgeom, LWPOLY* ppoly) {
    ppoly->nrings = 7;
    pgeom->data = 0;
    std::cout << ppoly->nrings << '\n';
}

int main() {
    LWGEOM geom = {};
    LWGEOM* pgeom = &geom;
    LWPOLY* ppoly = (LWPOLY*)pgeom;
    f(pgeom, ppoly);
}

猜猜是什么,输出是7。