违反严格别名并不总是产生编译器警告

时间:2018-04-19 10:32:35

标签: c++ undefined-behavior strict-aliasing

严格别名有点把我扔进了一个循环。这是代码。

我有一个班级

Question.StartDate = (DateTime) rdr["StartDate"];


如果我使用它:

#include <arpa/inet.h>
#include <net/route.h>

class Alias
{
public:
   struct rtentry rt;
   struct sockaddr_in *address;  

   void try_aliasing()
   {
       address = (struct sockaddr_in *)&rt.rt_dst;
       address->sin_family = AF_INET;
   }
};


显示:

int main()
{
   Alias a ;
   a.try_aliasing();
   return 0;
}


但是,如果我将该课程用作:

warning:dereferencing pointer '<anonymous>' does break strict-aliasing rules

它编译得很好。
使用以下方式编译两次:

int main()
{
   Alias *a = new Alias();
   a->try_aliasing();
   return 0;
}

已经查看了严格别名的一些主题,但他们未能为我清除这种行为的原因。

1 个答案:

答案 0 :(得分:0)

在大多数编译器能够生成“严格别名”警告的情况下,他们可以很容易地识别使用不同左值的存储操作之间的关系。标准不要求编译器使用不同类型的左值识别对存储的访问的原因是避免要求他们在没有理由期望它的情况下悲观地假设别名 <和em> [和因此没有理由发出任何关于它的警告]。

如上所述,标准不承认任何情况,其中非字符类型的左值可以从另一个左值导出并用于访问存储作为其自己的类型。甚至像:

struct foo {int x;} s = {0};
s.x = 1;

调用UB,因为它使用类型为int的左值来访问类型为struct foo的对象的存储。标准的作者依靠编译器编写者来识别常识意味着他们应该可预测地表现而不考虑标准是否真正需要它的情况。我不认为任何编译器是如此愚蠢,以至于不能识别s.x上的操作实际上是s上的操作,并且还有许多其他情况,标准的作者认为编译器会有认识到这些事情的感觉,而不是被命令这样做。

不幸的是,一些编译器编写者已经开始将这些规则视为理由,假设看起来像是使用另一个lvalues访问一种类型的存储的代码,而不是仅仅这样做,而不仅仅是对代码做出这样的假设。 不会看起来像这样。给出类似的东西:

void doSomehing(structs s2 *p);

void test(struct s1 *p)
{
  doSomething((struct s2*)p};
}

可以通过几种方式调用test之类的内容:

1. It might receive a pointer to a `struct s1`, which `doSomething` will need to operate upon [perhaps using the Common Initial Sequence guarantee] as though it is a `struct s2`.  Further, either:

1a. During the execution of `doSomething` storage accessed exclusively via pointers derived from a struct s2 like the one that was passed in will be accessed exclusively via such means, or...

1b. During the execution of `doSomething` storage accessed via things of that type will also be accessed via other unrelated means.

2. It might receive a pointer to a `struct s2`, which has been cast to a `struct s1*` for some reason in the calling code.

3. It might receive a pointer to a `struct s1`, which `doSomething` will process as though it's a `struct s1`, despite the fact that it accepts a parameter of type `struct s2`.

编译器可能会发现,很可能没有标准定义其行为的情况,因此决定在此基础上发出警告。另一方面,到目前为止最常见的情况是#1a,编译器确实应该能够以可预测的方式处理,无论标准是否需要,都可以通过确保对类型{ {1}}在函数内执行,在调用之前的类型struct s2上的操作和函数调用之后的类型struct s1上的操作之间进行排序。不幸的是,gcc和clang不这样做。