向量的 C++ 读取访问冲突
C++ Read access violation for vector
当我尝试使用 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 returns 我:抛出未处理的异常:读取访问冲突。
矢量是 0x6111F12.
我卡在这里了。如果您知道我应该做什么,我将不胜感激。提前致谢!
撇开由于严格别名违规而导致的所有未定义行为,在当前的英特尔芯片和 MSVC 运行时中,所有指针都是 48 位。
所以 0xffeeddccbbaa5577
永远不会 一个有效的指针值。
因此取消引用该值的行为将是未定义的。
如果您想将 data
分解为适当类型的四个元素,那么一种方法是创建 uint16_t foo[4]
say 和 memcpy
从 [= 开始的数据14=] 到 foo
.
如果要将其分配给指针,则需要获取该变量的地址
const uint16_t* vector = reinterpret_cast<const uint16_t*>( &data ) ;
注意:
这适用于 MSVC 2017,但是...
This is a truck load of undefined behaviour! – Bathsheba
正如 reinterpret_cast
的 cpprefrence 所说:
5) Any pointer to object of type T1
can be converted to pointer to object of another type cv T2
. This is exactly equivalent to static_cast<cv T2*>(static_cast<cv void*>(expression))
(which implies that if T2
's alignment requirement is not stricter than T1
's, the value of the pointer does not change and conversion of the resulting pointer back to its original type yields the original value). In any case, the resulting pointer may only be dereferenced safely if allowed by the type aliasing rules (see below)
...
Type aliasing.
Whenever an attempt is made to read or modify the stored value of an object of type DynamicType through a glvalue of type AliasedType, the behavior is undefined unless one of the following is true:
- AliasedType and DynamicType are similar.
- AliasedType is the
(possibly cv-qualified) signed or unsigned variant of DynamicType.
- AliasedType is std::byte (since C++17), char, or unsigned char: this
permits examination of the object representation of any object as an
array of bytes.
Note that many C++ compilers relax this rule, as a non-standard language extension, to allow wrong-type access through the inactive member of a union (such access is not undefined in C)
以上代码不满足任何别名规则。
通过通过强制转换获得的不同类型的指针访问数据,您进入了未定义行为领域。取而代之的是,尝试以下操作(注意我还用范围 for 循环替换了你的 while 循环,避免必须保留计数器)
#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
通过创建内存位置的副本来避免这种情况,您可以使用不同类型的指针安全地访问它。另请查看 type-punning (as pointed out by @DanielLangr)
这真的很容易,但是您 如此 与最初的尝试相去甚远,以至于让所有人都感到困惑。
uint16_t vector[] = { 0x5577, 0xbbaa, 0xddcc, 0xffee };
提出正确的问题,如果您在评论中提出了您的问题,我们会更快到达那里。
这是一个具体示例,应该避免由于严格的别名/"illegal" 强制转换等而导致的任何未定义行为,因为这似乎是您真正感兴趣的。
此代码取一个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 << "\n\n";
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
当我尝试使用 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 returns 我:抛出未处理的异常:读取访问冲突。 矢量是 0x6111F12.
我卡在这里了。如果您知道我应该做什么,我将不胜感激。提前致谢!
撇开由于严格别名违规而导致的所有未定义行为,在当前的英特尔芯片和 MSVC 运行时中,所有指针都是 48 位。
所以 0xffeeddccbbaa5577
永远不会 一个有效的指针值。
因此取消引用该值的行为将是未定义的。
如果您想将 data
分解为适当类型的四个元素,那么一种方法是创建 uint16_t foo[4]
say 和 memcpy
从 [= 开始的数据14=] 到 foo
.
如果要将其分配给指针,则需要获取该变量的地址
const uint16_t* vector = reinterpret_cast<const uint16_t*>( &data ) ;
注意: 这适用于 MSVC 2017,但是...
This is a truck load of undefined behaviour! – Bathsheba
正如 reinterpret_cast
的 cpprefrence 所说:
5) Any pointer to object of type
T1
can be converted to pointer to object of another typecv T2
. This is exactly equivalent tostatic_cast<cv T2*>(static_cast<cv void*>(expression))
(which implies that ifT2
's alignment requirement is not stricter thanT1
's, the value of the pointer does not change and conversion of the resulting pointer back to its original type yields the original value). In any case, the resulting pointer may only be dereferenced safely if allowed by the type aliasing rules (see below)...
Type aliasing. Whenever an attempt is made to read or modify the stored value of an object of type DynamicType through a glvalue of type AliasedType, the behavior is undefined unless one of the following is true:
- AliasedType and DynamicType are similar.
- AliasedType is the (possibly cv-qualified) signed or unsigned variant of DynamicType.
- AliasedType is std::byte (since C++17), char, or unsigned char: this permits examination of the object representation of any object as an array of bytes.
Note that many C++ compilers relax this rule, as a non-standard language extension, to allow wrong-type access through the inactive member of a union (such access is not undefined in C)
以上代码不满足任何别名规则。
通过通过强制转换获得的不同类型的指针访问数据,您进入了未定义行为领域。取而代之的是,尝试以下操作(注意我还用范围 for 循环替换了你的 while 循环,避免必须保留计数器)
#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
通过创建内存位置的副本来避免这种情况,您可以使用不同类型的指针安全地访问它。另请查看 type-punning (as pointed out by @DanielLangr)
这真的很容易,但是您 如此 与最初的尝试相去甚远,以至于让所有人都感到困惑。
uint16_t vector[] = { 0x5577, 0xbbaa, 0xddcc, 0xffee };
提出正确的问题,如果您在评论中提出了您的问题,我们会更快到达那里。
这是一个具体示例,应该避免由于严格的别名/"illegal" 强制转换等而导致的任何未定义行为,因为这似乎是您真正感兴趣的。
此代码取一个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 << "\n\n";
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