是什么解释了这个C代码的输出?

use*_*401 0 c

#include <stdio.h>

struct abc{
  int a;
  int b;
} xyz;

int main()
{
  xyz.a = 10;
  xyz.b = 20;
  printf("%d %d", xyz, xyz.a);
}
Run Code Online (Sandbox Code Playgroud)

上述程序的输出是10 20.

如果我添加另一个printf语句为

printf("%d %d %d", xyz, xyz.a, xyz.b);
Run Code Online (Sandbox Code Playgroud)

输出来了10 20 10.

对此有何解释?

pax*_*blo 15

这是因为调用printf整个结构 xyz推送到堆栈上,并且该结构(在本例中)由两个整数组成.的xyz.a,因为它超出了该堆栈区在这种情况下被忽略printf关心.

虽然这种行为是未定义(一)让任何事情都可能发生,这种特殊情况下可以解释,因为printf("%d %d",xyz,xyz.a);声明可能推xyzxyz.a到堆栈是这样的:

xyz.a | 10 |    |
xyz   | 20 |    | Stack grows downward.
      | 10 |    V
Run Code Online (Sandbox Code Playgroud)

printf代码本身,因为它被赋予了两个%d,将在底部打印10和20.换句话说,它是格式字符串和参数之间的不匹配.

当你添加另一个时%d,它打印它认为是第三个参数(但实际上是第二个参数),上图中的前10个参数.

我应该提一下,依靠这种行为并不是一个好主意.当您切换编译器,编译器的版本,甚至可能在奇数天时,它可能会改变:-)

好的编译器gcc实际上会查看printf参数内部以将此作为潜在错误:

pax$ cat qq.c
#include<stdio.h>
struct abc { int a; int b; } xyz;
int main (void) {
    xyz.a=10;
    xyz.b=20;
    printf("%d %d",xyz,xyz.a);
    return 0;
}

pax$ gcc -Wall -o qq qq.c
qq.c: In function 'main':
qq.c:6: warning: format '%d' expects type 'int',
        but argument 2 has type 'struct abc'
qq.c:6: warning: format '%d' expects type 'int',
        but argument 2 has type 'struct abc'
Run Code Online (Sandbox Code Playgroud)

(a)从c99,section 7.19.6.1/9:如果任何参数不是相应转换规范的正确类型,则行为未定义.