当我尝试使用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。
我被困在这里。如果您有任何想法,我将不胜感激。预先感谢!
答案 0 :(得分:5)
搁置由于严格别名违反而获得的所有未定义行为,在当前的Intel芯片和MSVC运行时中,所有指针均为48位。
因此0xffeeddccbbaa5577
从不是有效的指针值。
因此取消引用该值的行为将是不确定的。
如果您想将data
分解为适当类型的四个元素,则一种方法是创建一个uint16_t foo[4]
的声明,并memcpy
始于{{1} }到&data
。
答案 1 :(得分:4)
通过使用不同类型的指针访问数据,该指针是通过将您漫游到 undefined-behavior-land 而获得的。替代此方法,请尝试以下操作(请注意,我也用有范围的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)
答案 2 :(得分:1)
这真的很容易,但是与原始尝试(让所有人感到困惑)相距很远。
uint16_t vector[] = { 0x5577, 0xbbaa, 0xddcc, 0xffee };
问正确的问题,如果您在评论中提出了问题,我们会更快地解决问题。
答案 3 :(得分:1)
这是一个具体的示例,应避免由于严格的别名/“非法”强制转换等导致任何未定义的行为,因为这似乎是您真正感兴趣的。
此代码采用一个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
答案 4 :(得分:-2)
如果要将变量分配给指针,则需要使用该变量的地址
const uint16_t* vector = reinterpret_cast<const uint16_t*>( &data ) ;
注意: 这适用于MSVC 2017,但是...
这是卡车的未定义行为! –芭丝谢芭
reinterpret_cast
的cpprefrence说:
5)任何指向
T1
类型的对象的指针都可以转换为指向另一cv T2
类型的对象的指针。这完全等同于static_cast<cv T2*>(static_cast<cv void*>(expression))
(这意味着如果T2
的对齐要求不严格于T1
的对齐要求,则指针的值不会更改,并且结果指针的转换返回其原始类型会产生原始值)。无论如何,只有在类型别名规则允许的情况下,才能安全地取消对结果指针的引用(请参见下文)...
类型别名。 每当尝试通过AliasedType类型的glvalue读取或修改DynamicType类型的对象的存储值时,除非满足以下条件之一,否则行为是不确定的:
- AliasedType和DynamicType相似。
- AliasedType是 (可能具有CV资格)DynamicType的有符号或无符号变体。
- AliasedType是std :: byte(从C ++ 17开始),char或unsigned char: 允许将任何对象的对象表示形式检查为 字节数组。
请注意,许多C ++编译器都放宽了此规则(作为非标准语言扩展),以允许通过联合的不活动成员进行错误类型的访问(此类访问在C中并非未定义)
上面的代码不满足任何别名规则。