#include <stdio.h>
typedef struct ss {
int a;
char b;
int c;
} ssa;
int main(){
ssa *ss;
int *c=&ss->a;
char *d=&ss->b;
int *e=&ss->c;
*c=1;
*d=2;
*e=3;
printf("%d=%p %d=%p %d=%p\n",*c,c++,*c,c++,*c,c);
return 0;
}
//prints 1=0x4aaa4333ac68 2=0x4aaa4333ac6c 3=0x4aaa4333ac70
My thinking of how should be the memory structure:
int | char | int
(68 69 6A 6B) (6C) (6D 6E 6F 70)
我试图理解这段代码在内存中是如何工作的。
为什么int * e从0x ... 70开始?
为什么来自char(6C)的c ++(increment)会增加4个字节?
感谢。
答案 0 :(得分:3)
首先,这些行是非法的:
*c=1;
*d=2;
*e=3;
你所拥有的只是一个指向ssa
的指针,但你实际上没有为指向对象分配任何空间。因此,这3行试图写入未分配的内存,并且您有未定义的行为。
内存中的结构布局使得成员字段的内存地址不断增加,但是出于对齐的原因,编译器可以在其间放置任意数量的填充,尽管共享相同初始元素的2个结构将具有相应的成员。相同的偏移。这是可以证明成员地址之间存在“差距”的原因之一。
您应该更加小心地致电printf()
。参数评估顺序未定义。您正在两个序列点之间多次更改c
的值(请参阅Undefined behavior and sequence points)。此外,指针算法只能保证在使用指向同一数组的元素或超过结尾的元素执行时才能正常工作。
因此,简而言之:代码在整个地方都有未定义的行为。 任何都可能发生。一个更好的方法是:
#include <stdio.h>
typedef struct ss {
int a;
char b;
int c;
} ssa;
int main() {
ssa ss = { 0, 0, 0 };
int *c = &ss.a;
char *d = &ss.b;
int *e = &ss.c;
printf("c=%p d=%p e=%p\n", (void *) c, (void *) d, (void *) e);
return 0;
}
施展到void *
是必要的。您可能会在d
和e
的值之间看到3个字节的间隔,但请记住,这是高度依赖平台的。
答案 1 :(得分:1)
结构内部经常有填充,你不能假设每个字段都紧跟在它之前。
编译器添加填充以使结构成员快速访问,有时为了使成为可能。并非所有处理器都支持未对齐的访问,即使那些处理器也会对此类访问产生性能损失。
您可以使用offsetof()
找出填充的位置,但通常您不应该关心。