Can';我不明白为什么我在C中使用struct offset得到这些结果

Can';我不明白为什么我在C中使用struct offset得到这些结果,c,struct,offset,C,Struct,Offset,我在玩结构并尝试使用偏移量获取它们的值,这是我的代码 #include <stdio.h> #include <stddef.h> typedef struct abcd{ int a,b; double c,d; }abcd; int main() { abcd teste = {.a = 3, .b = 5, .c = 7, .d = 9}; printf("value of a: %d //value of b: %d\n",

我在玩结构并尝试使用偏移量获取它们的值,这是我的代码

#include <stdio.h>
#include <stddef.h>

typedef struct abcd{
    int a,b;
    double c,d;
}abcd;

int main()
{
    abcd teste = {.a = 3, .b = 5, .c = 7, .d = 9};
    printf("value of a: %d  //value of b:  %d\n",*( (char*) &teste), *((char*) &teste + offsetof(abcd, b)) );
    return 0;
}
我得到输出:
a的值:5:b的值:1360854088

为什么会发生这种情况

printf("value of a: %d  value of b: %d\n", *( &teste), *((char*) &teste + offsetof(abcd, b)) );
这将通过值传递teste,这比单个int占用更多的空间。第二个
%d
可能会从第一个arg的某些字节获取输入。编译器警告明确了这一点:

$ clang-3.5 -Wall  bad-printf.c -O3 
bad-printf.c:12:48: warning: format specifies type 'int' but the argument has type 'abcd' (aka 'struct abcd') [-Wformat]
    printf("value of a: %d  value of b: %d\n", *( &teste), *((char*) &teste + offsetof(abcd, b)) );
                        ~~                     ^~~~~~~~~~

$ gcc -Wall  bad-printf.c -O3 
bad-printf.c: In function ‘main’:
bad-printf.c:12:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘abcd’ [-Wformat=]
     printf("value of a: %d  value of b: %d\n", *( &teste), *((char*) &teste + offsetof(abcd, b)) );
     ^

$ ./a.out 
value of a: 5  value of b: 0

$ uname -a
Linux tesla 3.19.0-22-generic #22-Ubuntu SMP Tue Jun 16 17:15:15 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
它还将一个单字节字符作为第三个参数(格式字符串后的第二个参数)传递给
printf
。寄存器中的其他字节(或堆栈上的其他字节,如果您为过时的32位x86编译的话)可能是其他字节留下的

检查装配输出。您可能会发现从
&abcd.b
加载了一个字节,而其他字节则保持不变


您已经告诉printf(通过使用
%d
)您传递了一个完整的
int
。如果你只想打印一个8位整数(所以它不会把填充当作数据),你需要一个大小前缀到你的格式说明符。

Trff%d,但是你通过SturCT ADCD,这是一个未定义的动作,结果是未定义的,它应该考虑Prtf.c实现。 我的代码:

 typedef struct abcd{
        int a,b;
            double c,d;
}abcd;

int main()
{
    abcd teste = {.a = 3, .b = 5, .c = 7, .d = 9}; 
    printf("value of a: %d  //value of b:  %d\n",*( (char*) &teste), *((char*) &teste + offsetof(abcd, b)) );
    printf("%d\n", offsetof(abcd, b));
    printf("value of a: %p  value of b: %p\n", ( &teste), ((char*) &teste + offsetof(abcd, b)) );
    printf("value of a: %d  value of b: %d\n", teste, *((char*) &teste));
    printf("value of a: %p  value of b: %p\n", &teste, ((char*) &teste));
    printf("value of a: %d  value of b: %d\n", teste, *((char*) &teste));
    //No casting to (char*) in value of a
    return 0;
}
result:
value of a: 3  //value of b:  5
4
value of a: 0x7fff86f203b0  value of b: 0x7fff86f203b4
value of a: 3  value of b: -2114388464
value of a: 0x7fff86f203b0  value of b: 0x7fff86f203b0
value of a: 3  value of b: -2114388464

未定义的过程导致未定义的结果

您的第二个
printf
实际上是为
%d
格式说明符提供了完整的结构(
*(&teste)
)。这将使格式字符串中后续说明符的后续值的堆栈位置不对齐。类型转换在C编程中有着悠久的传统,对于正确使用返回
void*
类型的
malloc()
之类的东西是必要的。我不确定GRC是怎么回事。@larsks在C中你不应该抛出一个
void*
,特别是对于
malloc
void*
可以分配给任何非函数指针类型,而无需强制转换。然而,C++是一个不同的故事。@ GRC在C?@ GRC中的类型化时违反了什么标准,讨论一般不是关于铸造,而是关于铸造<代码> Value*/Cuff>。OP的例子并非如此。
 typedef struct abcd{
        int a,b;
            double c,d;
}abcd;

int main()
{
    abcd teste = {.a = 3, .b = 5, .c = 7, .d = 9}; 
    printf("value of a: %d  //value of b:  %d\n",*( (char*) &teste), *((char*) &teste + offsetof(abcd, b)) );
    printf("%d\n", offsetof(abcd, b));
    printf("value of a: %p  value of b: %p\n", ( &teste), ((char*) &teste + offsetof(abcd, b)) );
    printf("value of a: %d  value of b: %d\n", teste, *((char*) &teste));
    printf("value of a: %p  value of b: %p\n", &teste, ((char*) &teste));
    printf("value of a: %d  value of b: %d\n", teste, *((char*) &teste));
    //No casting to (char*) in value of a
    return 0;
}
result:
value of a: 3  //value of b:  5
4
value of a: 0x7fff86f203b0  value of b: 0x7fff86f203b4
value of a: 3  value of b: -2114388464
value of a: 0x7fff86f203b0  value of b: 0x7fff86f203b0
value of a: 3  value of b: -2114388464