在处理其他问题时,我需要创建一些指向任意选定内存区域的指针,以便能够查找内存值。这些实验给我带来了有趣的问题和疑问。
考虑以下代码:
//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.TestArr1
是0x11,0x11,0x11,0x11
StructLook.TestArr2
是0x22,0x22,0x22,0x22
等等。
问题是:
如何记录和解释指针的“附加”维度这一特性?请注意,指针导航时使用 [n][x] 表示法,即使该指针被声明为一维数组。
为什么以这种方式定义的指针的内存对齐会使值在内存中“垂直”呈现?迭代第一个索引时,即
&(MemLookup1[1])
给我们地址MemLookup1[0] + size of element pointed by pointer
而不是更自然的数组或字符本身的第二个元素。如何创建满足我要求的数组类型指针?
最后但并非最不重要的一点:为什么当数组包裹在结构周围时它工作得很好?
StructLook
给了我我所需要的,对内存单元的线性查找。
编辑
Pics来自调试器。 代码是针对 C(MinGW + GDB)编译的
最佳答案
因为你的代码非常像 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 = data
, MemLookup1 = &data[0]
,或类似的。
尽管 C 语言没有定义程序的行为,但如果可以编译它,那么我们确实可以使用调试器来尝试查看某些特定运行中实际发生的情况。请注意,C 并不保证每次运行时都是相同的,甚至也不保证程序不会以某种方式与调试器不兼容,但希望是永恒的。
你就在这里跌倒了。您声称通过指针MemLookup1
获得了不同的数据 View 比你通过指针 StructLook
所做的更多,但是调试器窗口图像中显示的表达式并不相似。例如,您似乎对 StructLook->TestArr1[1]
感到惊讶与 *MemLookup1[1]
的值不同,但这是可以预料的。
正如我们已经确定的,MemLookup1
是一个指向四个数组的指针 unsigned char
。 MemLookup1[1]
因此指定 MemLookup1[0]
之后的数组在内存中。在本例中,调试器显示 MemLookup1
和StructLook
都是 data
的别名,所以MemLookup1[1]
是指向 data[1]
的指针,而StructLook->TestArr1
是 data[0]
的别名。数组索引的优先级高于指针取消引用,在这种情况下,与大多数其他情况一样,数组值表达式会衰减为指向数组第一个元素的指针,因此 *MemLookup1[1]
相当于 data[1][0]
。与(*MemLookup1)[1]
对比,相当于data[0][1]
。另请注意 (*MemLookup1)[1]
形式的相似性以及声明形式MemLookup1
.
这与 temp1
有什么关系... temp5
尚不清楚。您的调试 View 不会显示与这些相关的任何表达式。
关于c - 数组映射选定的内存区域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34296534/