s1,& s1和& s1.a(结构)之间的差异

时间:2014-10-07 08:49:39

标签: c structure

结构变量在不与.运算符一起使用时包含什么?

节目下面的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中没有地址运算符。)

有人能清楚我在这里做了什么吗?或者只是一个编译器问题?

5 个答案:

答案 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来撤销变量(显然不存在,因为我们没有传输它)并且它撤回了随机垃圾值。关于s1s1.a具有相同的地址 - 这是因为整数a是结构scratch中的第一个变量,因此当您请求{{1}的地址时你请求它开始的第一个字节(虽然这里是一个a因此它只有一个字节),结构本身(作为一个结构)不会消耗一些额外的内存所以chars1具有相同的地址,因为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)的地址时,你打印出它们存储的实际存储地址 - 在两种情况下都是相同的。这是一件有效的事情。