结构变量在不与.
运算符一起使用时包含什么?
节目下面的Conisder
#include<stdio.h>
typedef struct{
char a;
int b;
} scratch;
int main(){
scratch s1 = {2,4};
printf("%p",s1); o/p 000566000
printf(" %p",&s1); o/p 00000420
printf(" %p",&s1.a); o/p 00000420
return 0;
}
sturct变量s1
及其第一个成员s1.a
在与&
一起使用时返回相同的地址,但s1
会返回其他值。这是垃圾还是什么?
struct s1包含什么? (当我用oops语言执行此操作时,对象变量会打印一些关于java的地址,并且java中没有地址运算符。)
有人能清楚我在这里做了什么吗?或者只是一个编译器问题?
答案 0 :(得分:3)
您的所有printf
声明都是非法的。
printf("%p",s1);
类型scratch
在预期void*
时通过。这会导致未定义的行为。
printf("%p",&s1);
类型scratch*
在预期void*
时通过。这导致未定义的行为。请改用printf("%p",(void*)&s1);
。
printf("%p",&s1.a);
类型char*
在预期void*
时通过。这导致未定义的行为。请改用printf("%p",(void*)&s1.a);
。
答案 1 :(得分:2)
此:
printf("%p",s1);
无效且可能是未定义的行为。格式说明符%p与您的结构不兼容。如果您启用警告,GCC会告诉您:
format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘scratch’ [-Wformat]
答案 2 :(得分:2)
关于printf("%p", s1);
- 它是一个垃圾值,因为它(结构)与格式说明符%p
不兼容,因为它不是指针 - 它不是关于编译器 - 它是关于函数printf()
以及varargs的行为 - 请注意,当您只键入printf("%d");
时,它将打印一个值,即当时在堆栈内存中找到的随机值 - printf()
以为你转移了2个参数,一个格式字符串和一个与格式说明符匹配的值,所以他使用varargs来撤销变量(显然不存在,因为我们没有传输它)并且它撤回了随机垃圾值。关于s1
和s1.a
具有相同的地址 - 这是因为整数a
是结构scratch
中的第一个变量,因此当您请求{{1}的地址时你请求它开始的第一个字节(虽然这里是一个a
因此它只有一个字节),结构本身(作为一个结构)不会消耗一些额外的内存所以char
和s1
具有相同的地址,因为s1.a
实际上是结构的第一个字节。
答案 3 :(得分:0)
&amp; s1是s1的地址。 &amp; s1.a是s1.a的地址,它与s1的地址相同,因为&#34; a&#34;是结构的第一个元素。
现在,&#34;%p&#34;用于打印指针地址。 s1是结构实例,而不是地址,因此不应使用&#34;%p&#34;打印。
答案 4 :(得分:0)
你确定你的输出正确吗?
printf("%p",s1)
将取s1的值(即它代表的字节,取决于你如何编译它,以及目标机器架构),并将其视为指针。它无论如何都会生成编译器警告 -
test.c:10:15: warning: format specifies type 'void *' but the argument has type 'scratch' [-Wformat]
对于解包结构,char将占用4个字节(在大多数系统上,实现定义)。结构将如下布局。
因此,s1内存中的布局(在小端系统上) 0x02(字符)0x000000(3个字节填充)0x04000000(int)
如果在64位小端系统(64位指针)上打印出来,它将指向8字节的指针地址,最小的字首先。
因此会打印出来 0x400000002 - 在大多数现代系统上,如果填充字节初始化为零,或者堆栈只是恰好包含零。如果堆栈不包含零,则4和2之间的字节可以包含任何内容。
当你打印出s1(&amp; s1)或s1.a(&amp; s1.a)的地址时,你打印出它们存储的实际存储地址 - 在两种情况下都是相同的。这是一件有效的事情。