简体   繁体   English

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

[英]C++ Read access violation for vector

Im getting an exception when I`m trying to use vector[int_number] and my program stop working. 当我试图使用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 me: Unhandled exception thrown: read access violation. Visual Studio 2017返回我:抛出未处理的异常:读取访问冲突。 vector was 0x6111F12. 向量是0x6111F12。

Im stuck here. 我卡在这里。 If you have any idea what I should do I`ll be grateful. 如果你知道我应该做什么,我将不胜感激。 Thanks in advance! 提前致谢!

Setting aside all the undefined behaviour you get due to strict aliasing violations, in the current crop of Intel chips and MSVC runtime, all pointers are 48 bits. 抛开由于严格的混叠违规而导致的所有未定义行为,在当前的Intel芯片和MSVC运行时,所有指针都是48位。

So 0xffeeddccbbaa5577 is never a valid pointer value. 所以0xffeeddccbbaa5577 永远不是一个有效的指针值。

So the behaviour on dereferencing that value will be undefined. 因此,取消引用该值的行为将是未定义的。

If you wanted to break up data , into four elements of an appropriate type, then one method is to create a uint16_t foo[4] say and memcpy the data starting at &data to foo . 如果你想将data拆分成适当类型的四个元素,那么一种方法就是创建一个uint16_t foo[4]来说并memcpy&datafoo开始的&data

By accessing the data through a pointer of different type you obtained by casting you wander off into undefined-behavior-land . 通过您通过投射获得的不同类型的指针访问数据,您漫游到undefined-behavior-land Instead of this, try the following (note I also replaced your while loop with a ranged for loop avoiding to have to keep a counter) 而不是这样,尝试以下(注意我也用一个范围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;
    }
}

yielding 生产

5577
bbaa
ddcc
ffee

If you use reinterpret_cast you hold two pointers of different type pointing to same address which may easily lead to undefined behavior. 如果使用reinterpret_cast则会保存两个指向同一地址的不同类型的指针,这可能很容易导致未定义的行为。 memcpy avoids that by creating a copy of the memory location and you may safly access it with a pointer of a different type. memcpy通过创建内存位置的副本来避免这种情况,您可以使用不同类型的指针安全地访问它。 Also take a look into type-punning (as pointed out by @DanielLangr) 还要看看类型惩罚(正如@DanielLangr指出的那样)

It's really very easy, but you were so far off with your original attempt that you've confused everyone. 这真的很容易,但是你与原先的尝试相距甚远,你每个人都感到困惑。

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

Ask the right question, if you'd asked the question you have in the comments we'd have got there a lot quicker. 问一个正确的问题,如果你在评论中提出问题我们会更快地到达那里。

Here's a concrete example that should avoid any undefined behavior due to strict aliasing / "illegal" casts / etc., since this seems to be what you're actually interested in. 这是一个具体的例子,应该避免由于严格的别名/“非法”强制转换/等等造成的任何未定义的行为,因为这似乎是你真正感兴趣的。

This code takes a std::uint64_t , copies it into an array of four std::uint16_t s, modifies the values in the array, and then copies them back into the original std::uint64_t . 此代码采用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';
}

With output (on my machine): 带输出(在我的机器上):

Original data:
18441921395520329079
Original, spliced data:
21879 48042 56780 65518

Modified data:
18441906281530414455
Modified, spliced data:
21879 48042 53261 65518

You need to take the address of that variable if you want to assign it to a pointer 如果要将该变量分配给指针,则需要获取该变量的地址

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

NOTE: This works on MSVC 2017, but... 注意:这适用于MSVC 2017,但......

This is a truck load of undefined behaviour! 这是卡车装载的未定义行为! – Bathsheba - 芭丝谢芭

As cpprefrence for reinterpret_cast says: 至于cpprefrence对reinterpret_cast说:

5) Any pointer to object of type T1 can be converted to pointer to object of another type cv T2 . 5)任何指向T1类型对象的指针都可以转换为指向另一种类型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). 这完全等同于static_cast<cv T2*>(static_cast<cv void*>(expression)) (这意味着如果T2的对齐要求不比T1更严格,则指针的值不会改变和转换结果指针返回其原始类型产生原始值)。 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的glvalue读取或修改DynamicType类型的对象的存储值时,除非满足下列条件之一,否则行为是未定义的:

  1. AliasedType and DynamicType are similar. AliasedType和DynamicType类似。
  2. AliasedType is the (possibly cv-qualified) signed or unsigned variant of DynamicType. AliasedType是DynamicType的(可能是cv限定的)有符号或无符号变体。
  3. 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. AliasedType是std :: byte(自C ++ 17开始),char或unsigned char:这允许将任何对象的对象表示检查为字节数组。

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) 请注意,许多C ++编译器放宽此规则作为非标准语言扩展,允许通过联合的非活动成员进行错误类型访问(此类访问在C中未定义)

The above code does not fulfill any of the Aliasing rules. 上述代码不符合任何别名规则。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM