0

我正在将数据缓冲区转换为大尺寸结构指针。它会引起任何问题吗?我在 Visual Studio 上尝试了以下代码,没有发现警告或错误。

#include <iostream>
using namespace std;

struct test
{
    char var1;
    char var2;
    long var3;
};
void function(char* data);

int main (void)
{
    char data[5] = {1, 0, 0, 3, 4};
    function(data);

    system("Pause");
    return 0;
}

void function(char* data)
{
    test* pTest = reinterpret_cast<test*>(data); // casting
    printf("%x\n", pTest->var1);
    printf("%x\n", pTest->var2);
    printf("%x\n", pTest->var3);
}
4

3 回答 3

4

您必须了解内存管理的工作原理。您静态分配了数组data,因此它将被放入堆栈(其中包含具有被调用函数的局部变量的帧)。堆栈是为每个进程静态分配的(这意味着,在进程的生命周期中,它的大小是恒定的)。

从现在开始,堆栈看起来更像这样:

data[1, 0, 0, 3, 4]

现在您调用了函数function。新框架被放入堆栈,所以它看起来更像这样:

data[1, 0, 0, 3, 4] | return-pointer[a b c d] pTest [e f a b]
(main data)           (function data)

现在,您将数据转换为您的类型,其大小至少为 6 个字节(假设它可能需要 8 个或更多字节,具体取决于类内容对齐方式)。所以你尝试访问这些字节:

data[1, 0, 0, 3, 4] | return-pointer[a b c d] pTest [e f a b]
(main data)           (function data)
     *  *  *  *  *                   *

(请注意,我的堆栈可视化被简化了,有可能在调用函数后还剩下更多数据)。

您在以后的 printf 中访问的所有内存都属于您的应用程序,因此操作系统不会引发访问冲突错误。您读取数据,因此您不会损坏任何东西。但现在假设,您将向pTest->var3. 这些字节将被覆盖:

data[1, 0, 0, 3, 4] | return-pointer[a b c d] pTest [e f a b]
(main data)           (function data)
     *  *  #  #  #                   #

现在看,您刚刚损坏了返回指针 - 很可能您的程序现在在尝试退出function并返回时崩溃main

通常强烈建议只转换兼容的数据类型(大小相等)。编译器通常无法知道您的强制转换是否有效(特别是如果您void *在途中强制转换指针)。所以你应该非常小心地在你的程序中制作演员表。

于 2013-05-17T06:12:16.957 回答
0

这种类型的转换是非常危险的(换句话说,你对编译器说 - “我知道我知道”),所以在这种情况下,你必须自己检查这种转换的正确性。

于 2013-05-17T06:01:58.507 回答
0

告诉编译器reinterpret_cast<xxx>(yyy)“相信我,我知道我在这里做什么”。这意味着您必须绝对确定自己所做的事情是正确的。

在这种特殊情况下,您会导致未定义的行为,因为您的结构大于您传入的数据,这绝对不是而且永远不是一件好事 - 它可能导致几乎任何事情发生(包括“类似于您expect") - 更糟糕的是,它可能会根据编译时使用的选项而有所不同,因此它可能看起来在调试模式下工作,然后在您在发布模式下编译时崩溃。至少var3会有一些未定义的内容,基于这样一个事实,即至少有一部分,不是所有的var3都在你定义的数据之外。这取决于 a 的大小和对齐方式long。在 Windows 中,这是 4 个字节并与 4 个字节对齐。long因此,您的两个 char 字段和数据之间有 2 个字节的空间。

但是,如果您知道自己在做什么,并且您不在代码中访问,则可以使用这种var3方案function

最后,如果这是通信协议的一部分,则可能需要从“填充是/需要添加什么”的角度来看待它。如果协议需要一定的间距,则需要正确处理——同时,处理器可能对“长”读取的对齐有严格的要求。因此,如果数据实际上是BYTE|BYTE|LONG打包在一起的,可能会说服编译器以这种方式打包数据结构,只是让处理器在访问“双字节对齐”长值时崩溃。

换句话说:在不是预期长度的数据上转换数据结构可能会导致各种问题,而编译器不会说任何话。

于 2013-05-17T07:19:49.623 回答