矢量的C++读取访问冲突

C++ Read access violation for vector

本文关键字:读取 访问冲突 C++      更新时间:2023-10-16

当我尝试使用vector[int_number]并且我的程序停止工作时,我得到了一个异常。

uint64_t data = 0xffeeddccbbaa5577;
uint16_t *vector = (uint16_t*) data;
int currentPosition = 0;
while (currentPosition <= 3) {
uint16_t header = vector[currentPosition]; // problem here

Visual Studio 2017返回我:引发未处理的异常:读取访问冲突。矢量为0x6111F12。

我被困在这里了。如果你知道我该怎么做,我将不胜感激。提前感谢!

抛开由于严格混叠违规而导致的所有未定义行为不谈,在当前的英特尔芯片和MSVC运行时中,所有指针都是48位。

因此0xffeeddccbbaa5577,而不是有效的指针值。

因此,取消引用该值的行为将是未定义的。

如果您想将data分解为四个适当类型的元素,那么一种方法是创建一个uint16_t foo[4],比如说memcpy,即从&datafoo开始的数据。

通过投射获得的不同类型的指针访问数据,您将进入未定义的行为领域。相反,请尝试以下操作(注意,我还将while循环替换为ranged for循环,以避免必须保留计数器)

#include <iostream>
#include <cstring>
int main() {
uint64_t data = 0xffeeddccbbaa5577;
uint16_t vector[4];
memcpy(vector, &data, sizeof(uint64_t));
for (uint16_t header : vector)
{
std::cout << std::hex << header << std::endl;
}
}

产生

5577
bbaa
ddcc
ffee

若您使用reinterpret_cast,您持有指向同一地址的两个不同类型的指针,这可能很容易导致未定义的行为。memcpy通过创建内存位置的副本来避免这种情况,并且您可以使用不同类型的指针安全地访问它。也可以看看类型双关语(如@DanielLangr所指出的)

这真的很容易,但你与最初的尝试相去甚远,以至于让所有人都感到困惑。

uint16_t vector[] = { 0x5577, 0xbbaa, 0xddcc, 0xffee };

问正确的问题,如果你在评论中问了你的问题,我们会更快地到达那里。

这里有一个具体的例子,应该可以避免由于严格的别名/"非法"强制转换等而导致的任何未定义的行为,因为这似乎是你真正感兴趣的。

此代码获取一个std::uint64_t,将其复制到由四个std::uint16_t组成的数组中,修改数组中的值,然后将它们复制回原始std::uint64_t

#include <cstdint>
#include <cstring>
#include <iostream>
int main() {
std::uint64_t data = 0xffeeddccbbaa5577;
std::uint16_t data_spliced[4];
std::memcpy(&data_spliced, &data, sizeof(data));
std::cout << "Original data:n" << data << "nOriginal, spliced data:n";
for (const auto spliced_value : data_spliced) {
std::cout << spliced_value << " ";
}
std::cout << "nn";
data_spliced[2] = 0xd00d;
memcpy(&data, &data_spliced, sizeof(data));
std::cout << "Modified data:n" << data << "nModified, spliced data:n";
for (const auto spliced_value : data_spliced) {
std::cout << spliced_value << " ";
}
std::cout << 'n';
}

输出(在我的机器上):

Original data:
18441921395520329079
Original, spliced data:
21879 48042 56780 65518
Modified data:
18441906281530414455
Modified, spliced data:
21879 48042 53261 65518

如果要将该变量分配给指针,则需要获取该变量的地址

const uint16_t* vector = reinterpret_cast<const uint16_t*>( &data ) ;

注意:这适用于MSVC 2017,但是。。。

这是一辆行为不明的卡车!–巴斯谢巴

正如reinterpret_cast的cpreference所说:

5)指向类型T1的对象的任何指针都可以转换为指向另一类型cv T2的对象的指针。这完全等同于static_cast<cv T2*>(static_cast<cv void*>(expression))(这意味着如果T2的对齐要求不比T1的更严格,则指针的值不会改变,并且将结果指针转换回其原始类型会产生原始值)。在任何情况下,只有在类型别名规则(见下文)允许的情况下,才能安全地取消对结果指针的引用

键入别名。每当试图通过AliasedType类型的glvalue读取或修改DynamicType类型对象的存储值时,除非以下情况之一为真,否则行为是未定义的:

  1. AliasedType和DynamicType相似
  2. AliasedType是(可能是cv限定的)DynamicType的有符号或无符号变体
  3. AliasedType是std::byte(从C++17开始)、char或unsigned char:this允许检查任何对象的对象表示字节数组

注意,许多C++编译器将此规则作为非标准语言扩展放宽,以允许通过联合的非活动成员进行错误类型的访问(这种访问在C中没有定义)

上述代码不满足任何别名规则。