违反严格别名并不总是会产生编译器警告
Violating strict aliasing does not always produce a compiler warning
严格的别名有点让我陷入循环。这是代码。
我有一堂课
#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
浏览了一些关于严格别名的线程,但他们未能为我清除这种行为的原因。
在大多数情况下,编译器能够生成"严格混叠"警告,它们同样可以使用不同的左值轻松识别存储上的操作之间的关系。 该标准不要求编译器使用不同类型的左值识别对存储的访问的原因是为了避免要求他们悲观地假设别名,否则他们没有理由期望它[因此没有理由发出任何警告]。
如前所述,该标准不承认非字符类型的左值可以从另一个左值派生并用于作为其自己的类型访问存储的任何情况。 甚至像这样:
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,编译器确实应该能够以可预测的方式处理它,无论标准是否要求,通过确保在函数中执行的对struct s2
类型事物的任何操作在调用之前对类型struct s1
的操作进行排序, 以及遵循函数调用的类型struct s1
上的那些。 不幸的是,gcc和clang没有这样做。
- 如何修复编译器警告 C6386 和 C6385?
- 编译器警告:执行到达值返回函数的末尾而不返回值
- 为什么布尔开关语句有编译器警告?
- 奇怪的缩小转换在 g++ 编译器中加倍到浮点警告
- 处理编译器关于可能丢失数据的警告的最优雅方法是什么
- 使用 reverse_iterator 而不是const_reverse_iterator并获得讨厌的编译器警告和错误
- 添加 c++11 编译器后打开 devc++ 时显示的警告
- 来自 std::chrono 的编译器警告,但未被使用
- 警告级别为 3 的 int 的 std::vector push_back 处的编译器警告
- G++ 编译器未为未定义的方法生成错误/警告
- 从 int 中剥离位时,编译器会警告一个转换,但不警告其他转换.有解决方法吗?
- 有没有办法在从临时返回按值string_view时获得编译器警告?
- 常量更改而不const_cast<> 为什么没有编译器警告/错误?
- 为什么编译器不在同一翻译单元中警告 ODR 违规
- C++语法错误,编译器不会警告或 int v = func(&v) 出错;
- C++ 添加编译器警告,以错误使用自定义打印/日志功能
- 我正在尝试在我的类中创建一个静态成员,但编译器警告我它是未定义的
- 是否可以将移动的变量标记为不再可用,并在使用它时收到编译器警告?
- 为什么我应该始终启用编译器警告
- 使用Boost :: black在boost :: variant中使用时,请警告编译器