【问题标题】:How does compound literals work in this code?复合文字在这段代码中是如何工作的?
【发布时间】:2012-12-01 15:50:09
【问题描述】:

我有以下代码,其中我编写了两个函数。两者都旨在产生相同的输出。但是具有循环的函数g() 产生的输出与我预期的不同,如下所示。

#include <stdio.h>

struct S { int i; };

void f(void)
{
    struct S *p;

    int i = 0;

    p = &((struct S) {i});
    printf("%p\n", p);

    i++;

    p = &((struct S) {i});
    printf("%p\n", p);
}

void g(void)
{
    struct S *p;

    for (int i = 0; i < 2; i++)
    {
        p = &((struct S) {i});
        printf("%p\n", p);
    }
}

int main()
{   
    printf("Calling function f()\n");
    f();

    printf("\nCalling function g()\n");
    g();
}

输出:

Calling function f()
0023ff20
0023ff24

Calling function g()
0023ff24
0023ff24

p的地址怎么和g()调用的时候一样?

【问题讨论】:

    标签: c gcc c99 compound-literals


    【解决方案1】:

    嗯,我不知道你到底想完成什么,但这里发生的是:

    • C99 中的 (struct S){i} 表示法将在堆栈上创建新的数据结构
    • 此数据结构在创建它的作用域结束时自动销毁

    所以在f() 函数中,您实际上在整个函数的范围内创建了两个不同的结构(即使您将它们的地址分配给同一个指针)——因此是两个不同的地址。

    void f(void)
    {
        struct S *p;
    
        int i = 0;
    
        p = &((struct S) {i}); // <- first data structure, let's call it A
        printf("%p\n", p);     // <- address of the structure A printed
    
        i++;
    
        p = &((struct S) {i}); // <- second data structure, let's call it B
        printf("%p\n", p);     // <- address of the structure B printed
    }                          // <- both A and B destroyed
    

    但是在g() 函数中,p 是在for 块的内部块中创建和销毁的,因此碰巧p 被一遍又一遍地分配在堆栈上的相同位置,始终给出同一个地址。

    void g(void)
    {
        struct S *p;
    
        for (int i = 0; i < 2; i++)
        {
            p = &((struct S) {i}); // <- data structure A created
            printf("%p\n", p);     // <- data structure A's address printed
        }                          // <- data structure A destroyed
    }
    

    【讨论】:

    • 我尝试将f() 包含在每个struct 的两个本地范围内,但它并没有改变结果,我想这很奇怪。
    • 谢谢。我以某种方式将&amp;((struct S) {i}) 混淆为静态存储对象。我没看到发生了什么。
    【解决方案2】:

    您应该检查汇编代码以确保,但我猜,因为p 是在循环范围内本地分配的,具有自动分配变量的地址(在堆栈上分配),它只是重用相同的空间在堆栈上。

    f() 中它不会这样做,因为两个结构在同一范围内共存,而在g() 编译器确定在第一次迭代结束时您将无法使用&amp;((struct S) {0})

    只是出于好奇在 gcc4.2 上使用 -O2 来查看是否有任何变化:

    Calling function f()
    0x7fff5fbff388
    0x7fff5fbff380
    
    Calling function g()
    0x7fff5fbff390
    0x7fff5fbff390
    

    【讨论】:

    • 只是好奇 - 你观察到 -O2 的变化是什么?我所看到的只是与以前相同的输出 - f 给出两个不同的地址,g 给出两个相同的地址..
    猜你喜欢
    • 1970-01-01
    • 2011-05-16
    • 2014-05-10
    • 2012-08-31
    • 2022-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多