数组映射选定的内存区域

时间:2015-12-15 18:16:06

标签: c arrays pointers casting

在处理其他一些问题时,我需要创建一些指向任意选定内存区域的指针,以便能够查找内存值。实验带给我有趣的问题和怀疑。

请考虑以下代码:

//Some hypothetical memory area simulation
unsigned char data[4][4] =
{
    {0x11,0x11,0x11,0x11}, //Memory areas 0x00 - 0x03
    {0x22,0x22,0x22,0x22}, //Memory areas 0x04 - 0x07
    {0x33,0x33,0x33,0x33},
    {0x44,0x44,0x44,0x44},
};

// Structure that wraps byte array
typedef struct
{
    unsigned char TestArr1[4];
    unsigned char TestArr2[4];
    unsigned char TestArr3[4];
    unsigned char TestArr4[4];
}structure_t;

//Pointer to array of 4 chars
unsigned char (*MemLookup1)[4];

structure_t *StructLook;

int main(void)

{
    //Set both tested variables on first address of test array
    MemLookup1 = &data;
    StructLook = &data;
    //Some helpers to visualize results
    unsigned char * temp1, *temp2, *temp3, *temp4, *temp5;
    temp1 = &MemLookup1[0][0];
    temp2 = &MemLookup1[0][1];
    temp3 = &MemLookup1[0][2];
    temp4 = &MemLookup1[0][3];
    temp5 = &MemLookup1[1][0];

}

MemLookup1被声明为指向4个字符数组的指针(根据THIS)。调试器下的结果对我来说很令人惊讶。

临时值如下:

*temp1 = 0x11
*temp2 = 0x22
*temp3 = 0x33
*temp4 = 0x44
*temp5 = 0x11 //在内存区域0x04

的值

StructLook.TestArr10x11,0x11,0x11,0x11

StructLook.TestArr20x22,0x22,0x22,0x22

等等。

问题是:

  1. 如何记录和解释指针的“附加”维度的此功能?请注意,在指针导航时使用[n] [x]表示法,即使该指针也被声明为单维数组。

  2. 为什么以这种方式定义的指针中的这种内存对齐会使值在内存中“垂直”显示?迭代第一个索引,即&(MemLookup1[1]),给我们MemLookup1[0] + size of element pointed by pointer的地址,而不是更自然,数组的第二个元素或字符本身。

  3. 如何创建满足我要求的数组类型指针?

  4. 最后但并非最不重要的一点:为什么当数组被包裹在结构周围时,这是完全正常的? StructLook给出了我所需要的,线性查找存储单元。

  5. 修改

    来自调试器的

    Pics。 代码是根据C(MinGW + GDB)

    编译的

1 个答案:

答案 0 :(得分:2)

由于您的代码非常类似于C,并且gcc成功编译了它 - 尽管有警告 - 所以我会回答C案例。

首先,我确认您的MemLookup1被声明为指向四个unsigned char数组的指针。我还观察到你的data被声明为包含四个unsigned char的四个数组的数组,因此data元素的类型与MemLookup1指向。

现在考虑这个任务:

MemLookup1 = &data;

右侧是指向由四个unsigned char组成的四个数组的数组的指针,但左侧指的是指向四个unsigned char数组的指针。这些是不兼容的类型,因此您的代码不满足简单赋值运算符的操作数的约束(由C2011在6.5.16.1/1表示),因此程序的行为是未定义的。类似适用于StructLook的分配。正确的分配是MemLookup1 = dataMemLookup1 = &data[0]或类似。

虽然C没有定义程序的行为,但是如果它可以被编译,那么我们确实可以使用调试器来尝试查看某些特定运行中实际发生的情况。 C并不保证每次运行都是一样的,请注意,甚至程序也不会在某种程度上与调试器不兼容,但希望永远是永恒的。

在这里,你跌倒了。您声称通过指针MemLookup1获得的数据视图与通过指针StructLook获得的视图不同,但调试器窗口图像中显示的表达式并不相似。例如,您似乎对StructLook->TestArr1[1]*MemLookup1[1]的价值不同感到惊讶,但这是可以预料的。

正如我们已经建立的那样,MemLookup1是指向四个unsigned char数组的指针。因此MemLookup1[1]在内存中指定MemLookup1[0]之后的数组。在这种情况下,调试器显示MemLookup1StructLook都是data的别名,因此MemLookup1[1]是指向data[1]的指针,而StructLook->TestArr1 }是data[0]的别名。数组索引的优先级高于指针解除引用,在此上下文中,与大多数其他索引一样,数组值表达式衰减为指向数组第一个元素的指针,因此*MemLookup1[1]等效于data[1][0] 。与(*MemLookup1)[1]对比,相当于data[0][1]。另请注意(*MemLookup1)[1]形式与MemLookup1声明形式的相似性。

这与temp1 ... temp5的关系尚不清楚。您的调试视图不会显示与这些相关的任何表达式。