使用C语言传递结构成员时的printf行为

udp*_*nil 2 c

我正在尝试一个程序来理解结构变量的行为,

示例代码:

struct temp
{
   int a;
   int b;
}obj;

int main()
{
   obj.a = 10;
   obj.b = 7;
   /* to see whether obj and &obj both are same 
    * I was verifying whether structure variables behave as arrays
    */
   printf("%d -- %p",obj,&obj); 
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

我期待输出为10和obj的地址但令我惊讶的是,实际输出为10和00000007

这对我来说很烦人!!!

谁能帮助我理解为什么printf正在接受第二个成员并打印它的价值.

Dan*_*uţă 7

发生这种情况是因为第一个参数预计有4个字节(一个int),但它有8个字节(struct obj).

当你将obj传递给printf函数时,它会将整个obj结构(包括b成员)放在堆栈上.因此,当打印时,第一个参数(obj.a)的堆栈中的前4个字节和第二个参数的堆栈中的下一个4个字节(obj.b).

看一下这个:

printf("%d %p %p\n", obj, &obj, &obj);
Run Code Online (Sandbox Code Playgroud)

  • 是和否 - 您必须注意填充.例如,`struct {char; int}`可能在char和int之间有空格以正确对齐.它很可能含有垃圾.你应该做的是传递`&obj`并在`obj-> a obj-> b`上打印'%d%d`. (2认同)

pax*_*blo 6

因为你正在推动obj堆栈.换句话说,你将10和7整数推到那里,其中一个用于%d,另一个用于%p.根本没有使用实际指针.

将行更改为:

printf("%d %d -- %p\n",obj,&obj);
Run Code Online (Sandbox Code Playgroud)

你会得到类似的东西:

10 7 -- 0x804a01c
Run Code Online (Sandbox Code Playgroud)

具有正确的地址:

这是帮助的图片:

What you push                 What printf uses
               +------------+
     /         |         10 |      %d
obj <          +------------+
     \         |          7 |      %p
               +------------+
&obj           | 0x80001234 |      not-used
               +------------+
Run Code Online (Sandbox Code Playgroud)

我已经看到了类似的问题,当人们传递longprintf%d整数格式说明.在%d仅使用的第一部分long,并与所有其他参数的第二部分的螺丝周围.详情请见此处.

这就是为什么当你使用printf函数族中的说明符不匹配类型时,gcc会弹出那些漂亮的小温暖消息:

qq.c: In function ‘main’:
qq.c:14: warning: incompatible implicit declaration of built-in function ‘printf’
qq.c:14: warning: format ‘%d’ expects type ‘int’, but argument 2
                  has type ‘struct temp’
Run Code Online (Sandbox Code Playgroud)


AnT*_*AnT 5

您可能会花费大量时间试图弄清楚为什么printf打印出所打印的内容甚至理解所有内容,后来才发现,在下一个实验中,完全清楚的解释不再有效,您必须开始一切从头开始。

在这种情况下,真正且普遍适用的解释是您的代码会产生未定义的行为。您%dprintf函数指定了格式说明符。这意味着相应的参数必须具有类型int,只有类型int而不是intint您提供的不是类型的对象,而不是struct tempstruct temp不是一个int。完成此操作后,代码的行为将是不确定的。它可以毫无意义地打印任何内容。它什么也不能打印。可能会崩溃。从形式上讲,它甚至可以格式化硬盘。该行为是不确定的。这意味着,即使您设法“了解”当前程序的行为,明天也可能会随机更改,原因仅仅是天气变化,日历上的日期已更改或编译器的版本已更改。

简而言之,您的代码毫无意义(特别是由于格式说明符的问题)。试图区分无意义的代码的行为是浪费时间。