3

Browsing through some old C code, and I came across this snippet. I am thoroughly confused as to what is happening behind the scenes.

I don't have a full understanding of struct pointer usage and operability, and I can't quite understand how the memory is being stored and accessed in the following code.

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);
}

This outputs

 myY->f1 = 4096
 myY->f2 = Stephen Goddard

After the cast, i1 is stored into myY->f1 and both ch1 & ch2 is stored in myY->f2. My question is how?. What does the memory content look like after the cast?

I know it has to do with the size of the struct and where the pointer is pointing (obviously), but after looking at this code, it has definitely made me realize my lack of understanding pointers.

Thank you

4

3 回答 3

6

记忆不受演员表的影响。强制转换只是将一个对象视为另一个不同类型的对象。如果您愿意,可以将代码视为具有union { struct x a; struct y b; },然后写入a但读取b.

这是未定义的行为,但碰巧出现的是各种对象相互重叠,因此您可以看到观察到的结果。

第一个strcpy(myX->ch1,"Stephen ");也是未定义的行为,因为缓冲区对于字符串来说太小了。

于 2013-09-08T21:19:12.830 回答
2

我假设int这里是 32 位的。后面的内存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

这是第二个之后发生的事情strcpy

      ----|----|--------|--------
Field  i1   i2     ch1      ch2
      ----|----|--------|--------
                Stephen  Goddard\0
                                 ^
                                 |
                           Zero terminator

请注意如何覆盖第一个终止的零strcpy以完成字符串。

这是布局struct y

Bit   00000000 001111111111222222
      01234567 890123456789012345
      --------|------------------
Field     f1            f2

当您投射 to 的指针时struct xstruct y您不会复制任何内容。的布局与千篇一律struct y的布局对齐,然后组合的内容通过“窗口”获取:struct xx.ch1x.ch2f2

        --------|------------------
Y Field    f1            f2
X Field  i1 | i2     ch1 |    ch2
        --------|------------------
                 Stephen  Goddard\0

就打印4096而言,这是未定义的行为:您将f1类型为 的 传递long long int到参数printf的位置int,因此printf将数据“重新解释”为int,切断上半部分(未定义的行为)。如果您使用适当的格式说明符,您获得的数字是17592186048512.

于 2013-09-08T21:31:06.417 回答
1

至于内存,它仍然只保存struct x最初malloced 的值加上两个指针myXmyY,都指向struct x

然而,它恰好从相同的相对内存索引 8 开始(并且ch1显然也是索引 0)并且也与 重叠,所以你得到:f2i1f1f2ch2

                      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

这是因为 along long和两个 s 一样长int,即 8 个字节。

于 2013-09-08T21:38:24.640 回答