C结构指针后面的内存内容
浏览一些旧的C代码,我发现了这个代码片段。我完全搞不清楚幕后发生了什么 我对结构指针的用法和可操作性没有完全的了解,我也不能完全理解在下面的代码中内存是如何存储和访问的C结构指针后面的内存内容,c,pointers,struct,C,Pointers,Struct,浏览一些旧的C代码,我发现了这个代码片段。我完全搞不清楚幕后发生了什么 我对结构指针的用法和可操作性没有完全的了解,我也不能完全理解在下面的代码中内存是如何存储和访问的 struct x{ int i1; int i2; char ch1[8]; char ch2[8]; }; struct y{ long long int f1; char f2[18]; }; int main(void) { struct x * myX; struct y * myY; myX = malloc(si
struct x{
int i1;
int i2;
char ch1[8];
char ch2[8];
};
struct y{
long long int f1;
char f2[18];
};
int main(void)
{
struct x * myX;
struct y * myY;
myX = malloc(sizeof(struct x));
myX->i1 = 4096;
myX->i2 = 4096;
strcpy(myX->ch1,"Stephen ");
strcpy(myX->ch2,"Goddard");
myY = (struct y *) myX;
printf("myY->f1 = %d\n", myY->f1);
printf("myY->f2 = %s\n", myY->f2);
}
这个输出
myY->f1 = 4096
myY->f2 = Stephen Goddard
强制转换后,i1
存储在myY->f1
中,ch1和ch2都存储在myY->f2
中。我的问题是怎么做?。演员阵容结束后,记忆内容是什么样子的
我知道这与结构的大小和指针指向的位置有关(很明显),但是在看了这段代码之后,它肯定让我意识到我对指针缺乏理解
谢谢演员阵容不会影响记忆。强制转换只是将一个对象视为另一个不同类型的对象。如果愿意,可以将代码想象为有一个
联合{struct x a;struct y b;}
,然后写入a
,但从b
读取
这是一种未定义的行为,但碰巧出现的情况是,各种对象相互重叠,因此您可以看到观察到的结果
第一个
strcpy(myX->ch1,“Stephen”)
也是未定义的行为,因为缓冲区对于字符串来说太小。我在这里假设为32位int
。struct x
后面的内存有24个字节,布局如下:
Bit 0000 0000 00111111 11112222
0123 4567 89012345 67890123
----|----|--------|--------
Field i1 i2 ch1 ch2
下面是在第一个strcpy之后发生的情况:
----|----|--------|--------
Field i1 i2 ch1 ch2
----|----|--------|--------
Stephen \0
^
|
Zero terminator
----|----|--------|--------
Field i1 i2 ch1 ch2
----|----|--------|--------
Stephen Goddard\0
^
|
Zero terminator
Bit 00000000 001111111111222222
01234567 890123456789012345
--------|------------------
Field f1 f2
下面是第二个strcpy之后发生的情况:
----|----|--------|--------
Field i1 i2 ch1 ch2
----|----|--------|--------
Stephen \0
^
|
Zero terminator
----|----|--------|--------
Field i1 i2 ch1 ch2
----|----|--------|--------
Stephen Goddard\0
^
|
Zero terminator
Bit 00000000 001111111111222222
01234567 890123456789012345
--------|------------------
Field f1 f2
注意第一个strcpy的终止零是如何被写入以完成字符串的
以下是结构y的布局图:
Bit 00000000 001111111111222222
01234567 890123456789012345
--------|------------------
Field f1 f2
当您将struct x
指针投射到struct y
时,您不会复制任何内容。struct y
的布局与struct x
的布局像饼干切割器一样对齐,然后通过f2
窗口获取组合的x.ch1
和x.ch2
的内容:
就打印
4096
而言,这是未定义的行为:您正在将f1
类型为long-long-int
的printf
传递到int
参数位置的printf
,因此printf
将数据重新解释为int
,切断上半部分(未定义的行为)。如果使用适当的格式说明符,得到的数字是17592186048512
至于内存,它仍然只保存最初malloc
ed的struct x
中的值,加上两个指针myX
和myY
,它们都指向struct x
然而,ch1
和f2
恰好从相同的相对内存索引8开始(显然,i1
和f1
也从索引0开始),并且f2
也与ch2
重叠,因此您得到:
i1 i2 ch1 ch2
from x's perspective: [int] [int] [char] [char] ... [char] ...
from y's perspective: [long long] [char] [char] ... [char] ...
f1 f2
0 4 8 9 16
这是因为一个
long-long
长度等于两个int
s,即8个字节。第一个strcpy
调用调用未定义的行为,因为它覆盖了一个不存在的数组元素,即ch1[8]
。我想我真正的问题是,在转换之后,myY->f2现在如何包含myX->ch1和ch2?@ElliotM:y
结构的f2
子对象与x
结构的ch1
子对象位于同一内存位置;第一个空终止符被第二个strcpy覆盖(注意缓冲区溢出)。为什么f1只存储4096而不是40964096?@ElliotM实际上,它存储17592186048512
。但是,您的程序告诉printf它是一个int
,因此%d
去掉其他四个字节。