严格的别名让我陷入了一个循环。这是代码。
我有一节课
#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;
}它编译得很好。
使用以下命令编译两次:
g++ a.cpp -Wall -O2我看过一些关于严格别名的帖子,但他们没有为我澄清这种行为的原因。
发布于 2018-04-23 02:33:43
在大多数情况下,编译器能够生成“严格别名”警告,它们可以很容易地识别使用不同左值的存储操作之间的关系。该标准没有要求编译器使用不同类型的左值来识别对存储的访问,这是为了避免要求他们悲观地假设别名,否则他们没有理由期待它,因此也没有理由发出任何关于它的警告。
如上所述,本标准不承认非字符类型的左值可以从另一个左值派生并作为自己的类型用于访问存储的任何情况。甚至像这样的东西:
struct foo {int x;} s = {0};
s.x = 1;调用UB,因为它使用类型为int的左值来访问类型为struct foo的对象的存储区。标准的作者依赖编译器编写者来认识到这样的情况,即常识意味着他们的行为应该是可预测的,而不考虑标准是否确实需要它。我认为任何编译器都不会愚蠢到没有意识到s.x上的操作实际上是s上的操作,而且还有许多其他情况,标准思想编译器的作者在没有接到命令的情况下也会意识到这样的事情。
不幸的是,一些编译器编写者已经开始将这些规则视为假设代码看起来会使用一种类型的左值访问另一种类型的存储,而不是这样做的理由,而不仅仅是对看起来不像这样的代码做出这样的假设。假设如下所示:
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,编译器确实应该能够以可预测的方式处理#1a,无论标准是否需要它,通过确保在函数中执行的对类型struct s2的任何操作在调用之前的类型struct s1上的操作和在函数调用之后的类型struct s1上的操作之间进行排序。不幸的是,gcc和clang没有做到这一点。
https://stackoverflow.com/questions/49918878
复制相似问题