我正在尝试一个程序来理解结构变量的行为,
示例代码:
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正在接受第二个成员并打印它的价值.
发生这种情况是因为第一个参数预计有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)
因为你正在推动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)
我已经看到了类似的问题,当人们传递long到printf与%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)
您可能会花费大量时间试图弄清楚为什么printf打印出所打印的内容甚至理解所有内容,后来才发现,在下一个实验中,完全清楚的解释不再有效,您必须开始一切从头开始。
在这种情况下,真正且普遍适用的解释是您的代码会产生未定义的行为。您%d为printf函数指定了格式说明符。这意味着相应的参数必须具有类型int,只有类型int而不是int。int您提供的不是类型的对象,而不是struct temp。struct temp不是一个int。完成此操作后,代码的行为将是不确定的。它可以毫无意义地打印任何内容。它什么也不能打印。可能会崩溃。从形式上讲,它甚至可以格式化硬盘。该行为是不确定的。这意味着,即使您设法“了解”当前程序的行为,明天也可能会随机更改,原因仅仅是天气变化,日历上的日期已更改或编译器的版本已更改。
简而言之,您的代码毫无意义(特别是由于格式说明符的问题)。试图区分无意义的代码的行为是浪费时间。