C ++ 11中严格的别名规则 [英] Strict aliasing rule in C++11

查看:159
本文介绍了C ++ 11中严格的别名规则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I use the following C structs in my C++11 code (the code comes from liblwgeom of PostGis, but this is not the core of the question). The code is compiled with the following options using g++-4.8:

-std=c++11 -Wall -Wextra -pedantic-errors -pedantic -Werror

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

and I don't get any errors during compilation (or warnings) (should I get any?)

在使用LWPOLY(实际上由LWGEOM*指出)时是安全的.我了解这是穷人的遗产,但这是我需要处理的.

Is safe to use LWPOLY (actually pointed by LWGEOM*) in functions that accept LWGEOM and don't modify the void *data; member. I understand that this is poor man's inheritance but this is what I need to work with.

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:

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;

执行类似操作时是否违反了严格的别名规则?

Am I violating strict aliasing rule when I do something like?

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

我知道在PostGis中,类型是专门设计为兼容"的,但是我想知道是否违反了该标准.

I know that in PostGis types are specifically designed to be "compatible" however I'd like to know if I am violating the standard by doing so.

此外,我注意到默认情况下,PostGis并未在禁用严格别名的情况下进行编译(至少是2.1.5版).

Also, I noticed that PostGis is not compiled with strict aliasing disabled by default (at least version 2.1.5).

我的同事帮助我进行了调查,似乎答案是:不,它没有违反严格的别名,但前提是我们访问的LWGEOMS成员的类型与LWPOLY的类型相同,并且位于该结构连续.这就是原因(引用标准):

My colleague helped me to investigate it and it seems the answer is No it doesn't violate strict aliasing, but only in case we access LWGEOMS members that are of the same type as of LWPOLY's and are laid out in the beginning of the struct contiguously. Here is why (quoting standard):

3.10.10说,您可以通过指向聚合或联合"的指针来访问成员.

3.10.10 says that you can access a member through a pointer to "aggregate or union".

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

8.5.1 defines aggregates (C structs are aggregates): An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

9.2.19说,对于标准布局类,指向该结构的指针与指向fist成员的指针相同(C结构为标准布局).

9.2.19 says that pointer to the struct is the same as pointer to the fist member for standard layout classes (C structs are standard layout).

这是否是一种安全的编码方式是另一个问题.

Whether this is a safe way to code is a different question.

推荐答案

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

Yes, it violates the strict aliasing rule. LWGEOM and LWPOLY are unrelated types, and so are int and void*. So, for example, modification to lwgeom->data may not be read through lwpoly->nrings and vice versa.

我使用GCC4.9对此进行了验证.我的代码如下:

I validated this with GCC4.9. My code is as follows:

#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.

Guess what, the output is 7.

这篇关于C ++ 11中严格的别名规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆