简体   繁体   English

这真的违反了严格的别名规则吗?

[英]Does this really break strict-aliasing rules?

When I compile this sample code using g++, I get this warning:当我使用 g++ 编译此示例代码时,我收到此警告:

warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]警告:取消引用类型双关指针将破坏严格别名规则[-Wstrict-aliasing]

The code:编码:

#include <iostream>

int main() 
{
   alignas(int) char data[sizeof(int)];
   int *myInt = new (data) int;
   *myInt = 34;

   std::cout << *reinterpret_cast<int*>(data);
}

In this case, doesn't data alias an int, and therefore casting it back to an int would not violate strict aliasing rules?在这种情况下, data是否不为 int 设置别名,因此将其转换回 int 不会违反严格的别名规则? Or am I missing something here?还是我在这里遗漏了什么?

Edit: Strange, when I define data like this:编辑:奇怪,当我这样定义data时:

alignas(int) char* data = new char[sizeof(int)];

The compiler warning goes away.编译器警告消失。 Does the stack allocation make a difference with strict aliasing?堆栈分配对严格别名有影响吗? Does the fact that it's a char[] and not a char* mean it can't actually alias any type?它是char[]而不是char*的事实是否意味着它实际上不能为任何类型设置别名?

The warning is absolutely justified.警告是绝对有道理的。 The decayed pointer to data does not point to an object of type int , and casting it doesn't change that.指向data的衰减指针不指向int类型的对象,并且转换它不会改变它。 See [basic.life]/7 :[basic.life]/7

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object , a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if :如果在一个对象的生命周期结束后,在该对象所占用的存储空间被重用或释放之前,在原对象所占用的存储位置创建一个新对象,一个指向原对象的指针一个指向该对象的引用引用原始对象,或者原始对象的名称将自动引用新对象,并且一旦新对象的生命周期开始,可用于操作新对象,如果
(7.1) — [..] (7.1) — [..]
(7.2) — the new object is of the same type as the original object (ignoring the top-level cv-qualifiers) , (7.2) —新对象与原始对象的类型相同(忽略顶级 cv 限定符)

The new object is not an array of char , but an int .新对象不是char数组,而是int P0137 , which formalizes the notion of pointing, adds launder : P0137 ,其指向形式化的概念,增加launder

[ Note : If these conditions are not met, a pointer to the new object can be obtained from a pointer that represents the address of its storage by calling std::launder (18.6 [support.dynamic]). [注意:如果不满足这些条件,则可以通过调用std::launder (18.6 [support.dynamic]) 从表示其存储地址的指针中获取指向新对象的指针。 end note ] 尾注]

Ie your snippet can be corrected thusly:即您的代码段可以这样更正:

std::cout << *std::launder(reinterpret_cast<int*>(data));

.. or just initialize a new pointer from the result of placement new, which also removes the warning. .. 或者只是从放置 new 的结果初始化一个新指针,这也消除了警告。

*myInt = 34; this expression is well-formed, because data provide storage for object of type int and myInt is a pointer to an object of type int.这个表达式是格式良好的,因为data为 int 类型的对象提供存储,而myInt是一个指向 int 类型对象的指针。 So, dereference such a pointer can access an object of type int.因此,取消引用这样的指针可以访问 int 类型的对象。

For *reinterpret_cast<int*>(data);对于*reinterpret_cast<int*>(data); this expression, it would violate the strict pointer aliasing.这个表达式,它会违反严格的指针别名。 Firstly, there's an array-to-pointer conversion that applied to data , The result is a pointer to the initial element of data ,it means the operand of reinterpret_cast<int*> is a pointer to a subject of data .首先,有一个应用于data的数组到指针的转换,结果是一个指向data初始元素的指针,这意味着reinterpret_cast<int*>的操作数是一个指向data主体的指针。
According to the following rule:根据以下规则:

If an object is created in storage associated with a member subobject or array element e, the created object is a subobject of e's containing object if:如果在与成员子对象或数组元素 e 关联的存储中创建对象,则创建的对象是 e 的包含对象的子对象,如果:

  • the lifetime of e's containing object has begun and not ended, and e 的包含对象的生命周期已经开始并且没有结束,并且
  • the storage for the new object exactly overlays the storage location associated with e, and新对象的存储正好覆盖与 e 关联的存储位置,并且
  • the new object is of the same type as e (ignoring cv-qualification).新对象与 e 的类型相同(忽略 cv 限定)。

An object of type int satisfy none of these rules. int 类型的对象不满足这些规则。 Hence, the operand of reinterpret_cast<int*> is not a pointer to an object that pointer-interconvertible with an object of type int.因此, reinterpret_cast<int*>的操作数不是指向可与 int 类型对象进行指针互转换的对象的指针。 So, The result of reinterpret_cast<int*> is not an pointer to an object of type int.因此, reinterpret_cast<int*>的结果不是指向 int 类型对象的指针。

a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined :程序尝试通过以下类型之一以外的泛左值访问对象的存储值,行为未定义

  • the dynamic type of the object.对象的动态类型。
  • [...] [...]

What about changing怎么改

std::cout << *reinterpret_cast<int*>(data);

to

int *tmp   = reinterpret_cast<int*>(data);
std::cout << *tmp;

? ?

In my case it got rid of the warning.就我而言,它消除了警告。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 严格混叠规则是否适用于函数调用? - Does the strict-aliasing rules apply across function calls? 警告! 取消引用类型化指针会破坏严格混叠规则[-Wstrict-aliasing] - warning! dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] 指针强制转换真的会破坏严格的别名吗? - Does pointer casting really break strict aliasing? 正在打破严格别名规则的演员 - A cast that is breaking strict-aliasing rules “解除引用类型惩罚指针将破坏严格别名规则”警告 - “dereferencing type-punned pointer will break strict-aliasing rules” warning C ++生成警告:取消引用类型标记的指针将破坏严格的别名规则 - C++ build warning : dereferencing type-punned pointer will break strict-aliasing rules stof()/ stoi()带有解引用类型指针的指针将破坏严格的混叠规则 - stof()/stoi() with dereferencing type-punned pointer will break strict-aliasing rules GCC警告“解除引用类型 - 惩罚指针将破坏严格别名规则” - GCC warning “dereferencing type-punned pointer will break strict-aliasing rules” GCC 7,aligned_storage和“解除引用类型惩罚指针将破坏严格别名规则” - GCC 7, aligned_storage and “dereferencing type-punned pointer will break strict-aliasing rules” 将char []强制转换为usigned int可以得到:取消引用类型标记的指针将破坏严格的别名规则 - Casting char[] to usigned int gives: dereferencing type-punned pointer will break strict-aliasing rules
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM