简体   繁体   English

在C语言中传递结构变量时的printf行为

[英]printf behaviour on passing a structure variable in C language

I was trying a program to understand the behavior of structure variable, 我正在尝试一个程序来理解结构变量的行为,

Sample code: 示例代码:

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;
}

I was expecting output to be 10 and address of obj But to my surprise, Actual output is 10 and 00000007 我期待输出为10和obj的地址但令我惊讶的是,实际输出为10和00000007

This is bugging me a lot now!!! 这对我来说很烦人!!!

Could anyone please help me understand why printf is taking second member and printing its value. 谁能帮助我理解为什么printf正在接受第二个成员并打印其价值。

This happens because the first parameter is expected to have 4 bytes (an int) but it has 8 bytes (struct obj). 发生这种情况是因为第一个参数预计有4个字节(一个int),但它有8个字节(struct obj)。

When you pass obj to printf function it will place on the stack the whole obj structure (including b member). 当你将obj传递给printf函数时,它会将整个obj结构(包括b成员)放在堆栈上。 So when printing it will take the first 4 bytes on the stack for 1st parameter (obj.a) and the next 4 bytes on the stack (obj.b) for 2nd parameter. 因此,当打印时,第一个参数(obj.a)的堆栈中的前4个字节和第二个参数的堆栈中的下一个4个字节(obj.b)。

Check this out: 看一下这个:

printf("%d %p %p\n", obj, &obj, &obj);

Because you're pushing obj onto the stack. 因为你正在把obj推到堆栈上。 In other words, you're pushing the 10 and 7 integers onto there and one of them is being used for the %d , the other for the %p . 换句话说,你将10和7整数推到那里,其中一个用于%d ,另一个用于%p The actual pointer isn't being used at all. 根本没有使用实际指针。

Change the line to: 将行更改为:

printf("%d %d -- %p\n",obj,&obj);

and you'll get something like: 你会得到类似的东西:

10 7 -- 0x804a01c

which has the correct address: 具有正确的地址:

Here's a picture to help out: 这是帮助的图片:

What you push                 What printf uses
               +------------+
     /         |         10 |      %d
obj <          +------------+
     \         |          7 |      %p
               +------------+
&obj           | 0x80001234 |      not-used
               +------------+

I've seen similar problems when people pass a long to printf with the %d integer format specifier. 当人们使用%d整数格式说明符将long传递给printf时,我遇到过类似的问题。 The %d only uses the first part of the long and the second part screws around with all the other arguments. %d仅使用long的第一部分,第二部分使用所有其他参数。 See here for details. 详情请见此处

That's why gcc has those nice little warming messages that pop up when you mismatch types with specifiers in the printf family of functions: 这就是为什么当你在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’

You might spend a lot of time trying to figure out why your printf prints what it prints and even understand everything, only to discover later, in your next experiment, that the explanation that was perfectly clear to you no longer works and you have to start everything from scratch. 您可能会花费大量时间来弄清楚为什么printf打印出打印的内容,甚至可以理解所有内容,只是为了稍后发现,在您的下一个实验中,您完全清楚的解释不再适用,您必须开始一切从头开始。

The real and universally applicable explanation in this case is that your code produces undefined behavior . 在这种情况下,真实且普遍适用的解释是您的代码产生未定义的行为 You specified a %d format specifier for the printf function. 您为printf函数指定了%d格式说明符。 That means that the corresponding argument must have type int , only int and nothing else than int . 这意味着相应的参数必须具有int类型,只有int而不是int Instead of an int you supplied an object of type struct temp . 您提供的是struct temp类型的对象,而不是int struct temp is not an int . struct temp不是int Once you did that, the behavior of your code is undefined. 一旦你这样做,代码的行为是不确定的。 It can print absolutely anything for no meaningful reason whatsoever. 无论出于何种意义,它都可以打印绝对任何东西。 It can print nothing. 它什么都不打印。 It can crash. 它会崩溃。 Formally, it can even format your hard drive. 形式上,它甚至可以格式化您的硬盘。 The behavior is undefined. 行为未定义。 Which means that even if you manage to "understand" the behavior of your program today, it might randomly change tomorrow just because the weather has changed, the date on the calendar has changed or the version of your compiler has changed. 这意味着,即使您设法“理解”当前程序的行为,它也可能会因为天气变化,日历上的日期发生变化或编译器版本发生变化而明天随机更改。

In short, your code makes no sense (specifically because of the issue with the format specifier). 简而言之,您的代码没有任何意义(特别是因为格式说明符的问题)。 Trying to pick apart the behavior of a meaningless code is a waste of time. 试图挑选无意义代码的行为是浪费时间。

The printf function takes the variable number of arguments. printf函数采用可变数量的参数。 This means that it doesn't know which parameters you passed to it at compile time. 这意味着它不知道您在编译时传递给它的参数。 Instead it tries to realize this at runtime by analyzing the format string you've passed. 相反,它试图通过分析您传递的格式字符串在运行时实现这一点。

printf("%d -- %p",obj,&obj);

The above code pushes the obj structure by value, which has a size of two integers. 上面的代码按值推送obj结构,其大小为两个整数。 Plus its address, which consumes a size of one more integer (assuming 32bit architecture). 加上它的地址,它消耗一个整数的大小(假设32位架构)。

On the other hand according to the format string you had to pass it one integer, and one address. 另一方面,根据格式字符串,您必须传递一个整数和一个地址。

You just confused it. 你只是把它搞糊涂了。 It considered the second struct member b to be the second parameter passed, and printed it as the pointer. 它认为第二个结构成员b是传递的第二个参数,并将其作为指针打印出来。 This explains the 00000007. 这解释了00000007。

This is what you had to do: 这是你必须做的:

printf("%d -- %p",obj.a,&obj);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM