我不明白为什么我不能用这种方式打印出b和c:
#include "stdio.h"
typedef struct{
int a;
int b;
int c;
} myStruct;
int main(){
myStruct MS;
MS.a = 13;
MS.b = 27;
MS.c = 39;
myStruct* pMS = &MS;
printf("pMS = %u\n", pMS );
printf("&a = %u\n", &pMS->a ); // addr of a is addr of struct
printf("&b = %u\n", &pMS->b ); // addr of b is +4 from a
printf("&c = %u\n", &pMS->c ); // addr of c is +8 from a
printf("*pMS = %d\n",*(pMS) );
printf("*pMS+4 = %d\n",*(pMS+4) );
printf("*pMS+8 = %d\n",*(pMS+8) );
}
终端显示b和c的虚假值(至少,我认为b和c应位于pMS + 4和pMS + 8):
gcc version 4.6.3
pMS = 1926301980
&a = 1926301980
&b = 1926301984
&c = 1926301988
*pMS = 13
*pMS+4 = 32765
*pMS+8 = 32765
答案 0 :(得分:3)
pMS+4
不整数的地址,位于结构开头之外的四个字节。指针的添加是根据指针类型进行缩放的,因此,如果它是指向整数的指针,则它将是超出开始的四个整数(如果你有32位整数,则为16个字节)。例如,见:
int someInt[2] = {4, 9}; // assume 4-byte int, big-endian
int *x = &someInt[0];
// | someInt[0] @ 0x1000 | someInt[1] @ 0x1004 |
// | 0,0,0,4 | 0,0,0,9 |
// | x = 0x1000 | x+1 = 0x1004 |
// | *(x) = 4 | *(x+1) = 9 |
然而,在你的情况下甚至更糟,因为你的指针是实际的结构。这意味着它按整个结构的大小缩放,三个完整的整数(如果需要加上填充。)
答案 1 :(得分:1)
此行例如
printf("*pMS+4 = %d\n",*(pMS+4) );
当你添加到指针时,它与索引到数组相同,所以等于:
printf("*pMS+4 = %d\n", pMS[4]);
当然没有数组,所以传递了伪结构值。
然后printf根本无法打印结构,%d会打印一些非感性的东西。
换句话说,双重未定义的行为。
答案 2 :(得分:-1)
通过对代码执行一些更改并实现@Jonathan Leffler
对评论的评论,这种方式对我有用。
<强> 代码 强>
#include <stdio.h>
struct t{
int a;
int b;
int c;
};
int main(){
struct t MS;
MS.a = 13;
MS.b = 27;
MS.c = 39;
struct t* pMS = &MS;
printf("pMS =%p\n", pMS );
printf("&a = %p\n", &pMS->a ); // addr of a is addr of struct
printf("&b = %p\n", &pMS->b ); // addr of b is +4 from a
printf("&c = %p\n", &pMS->c ); // addr of c is +8 from a
printf("*pMS.a = %d\n", (* ((int *) ((void *) pMS))));//13
printf("*pMS.b = %d\n", (* ((int *) ((void *) pMS)+1)));//27
printf("*pMS.c = %d\n", (* ((int *) ((void *) pMS)+2)));//39
return 0;
}
但是这也有效,正如你在@hyde中看到的那样用这种方式工作并不好。 C中的结构根据CPU体系结构打包,编译器意味着将struct成员放在打包形式中,例如在struct下面需要8个字节而不是5个。
struct example {
int a;
char b;
};
我用我的方式,因为我之前检查过,sizeof(void *), sizeof(int *)
都返回4。
考虑以下几点:
printf("*pMS.a = %d\n", (* ((int *) ((void *) pMS))));//13
printf("*pMS.b = %d\n", (* ((int *) ((void *) pMS)+1)));//27
printf("*pMS.c = %d\n", (* ((int *) ((void *) pMS)+2)));//39
为什么在括号内使用+1会导致访问我们的整数?
在我的系统中,整数数字占用4个字节,正如我在上面表达的void *
和int *
的大小相同4
字节。
首先删除void *
以简化(int *) (pMS) + 1
,将pMS表示为整数大小,当我们向其添加一个时,跳转到下一个指向27的字节地址。
我认为添加void *
用于从代码中删除UB,因为指针具有void *
类型指向结构的指针。
对于这种情况,删除void *
也有效。
最后
printf("pMS =%u\n", sizeof(MS) );//12(3 * 4)
printf("pMS =%u\n", sizeof(pMS) );//4
在我的平台上没有任何填充或打包,如上所示,整个结构保持12字节3整数,大小为4字节。
但pMs
是指向此结构的第一个地址的指针,因为第一个元素是整数,它有4个字节的大小。
<强> TODO 强>