【发布时间】:2015-05-31 15:39:59
【问题描述】:
我在我的 C++11 代码中使用了以下 C 结构(代码来自 PostGis 的 liblwgeom,但这不是问题的核心)。代码使用 g++-4.8 使用以下选项编译:
-std=c++11 -Wall -Wextra -pedantic-errors -pedantic -Werror
并且我在编译期间没有收到任何错误(或警告)(我应该收到任何错误吗?)
问题
在接受LWGEOM 并且不修改void *data; 成员的函数中使用LWPOLY(实际上是LWGEOM*)是安全的。我知道这是穷人的遗产,但这是我需要处理的。
详情
多边形:
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;
点阵:
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 中的类型是专门设计为“兼容”的,但是我想知道这样做是否违反了标准。
另外,我注意到 PostGis 编译时默认禁用严格别名(至少版本 2.1.5)。
解决方案
我的同事帮助我对其进行了调查,似乎答案是否定的,它不违反严格的别名,但仅在我们访问与 LWPOLY 的类型相同且布局在结构连续。原因如下(引用标准):
3.10.10 表示您可以通过指向“聚合或联合”的指针访问成员。
8.5.1 定义聚合(C 结构是聚合):
聚合是一个数组或一个类(第 9 条),没有用户提供的构造函数(12.1),没有私有或
受保护的非静态数据成员(第 11 条),无基类(第 10 条),无虚函数(10.3)。
9.2.19 表示指向结构的指针与指向标准布局类的第一个成员的指针相同(C 结构是标准布局)。
这是否是一种安全的编码方式是另一个问题。
【问题讨论】:
-
是的,这肯定会破坏字符串别名规则。
-
我个人的看法是,不应该在不同的结构之间进行转换,而应该解析它们。
-
这一行出现在标准中:“一种聚合或联合类型,在其元素或非静态数据成员(递归地包括元素或非静态数据)中包含上述类型之一子聚合或包含联合的成员)”,但我不确定我能否正确解释它
-
这可能是穷人的遗产。 (多边形是一种几何形状。)你能用你自己的类包装它们,从 LWGEOM 显式继承 LWPOLY 并进行动态或静态转换吗?库代码永远不会是别名安全的,但您自己的代码会。
-
@Alex 这是一个高性能库,解析会有点矫枉过正(我的主观意见)
标签: c++11 postgis strict-aliasing