问题 大小为1的数组与指向struct的指针


假设我有一个函数,它接受一个结构数组,定义如下:

void Foo(struct MyStruct *s, int count) {
    for (int i = 0; i < count; ++i) {
        // Do something with s[i]
    }
}

以下两个片段是否保证以相同的方式运行?

struct MyStruct s;
s.x = 0;
s.y = 0;
Foo(&s, 1);

struct MyStruct s[1]; // stack-allocated array of size 1
s[0].x = 0;
s[0].y = 0;
Foo(s, 1);

8971
2018-04-29 03:07


起源

godbolt.org/g/3iq38U 你可以看到他们生成了相同的机器代码 - Bryan Chen


答案:


答案是肯定的,它们实际上是一样的。首先,当在函数参数中使用时,数组作为指针传递给它的第一个元素。实际上,C中的所有对象都可以在存储方面被视为该类型的一个元素的数组。


6
2018-04-29 03:13





它们完全相同;证明 - 我为这两个代码示例编译并保存了MSVC 2015和GCC 4.9.3生成的汇编代码:

// Case 1: Pass by reference to single struct
typedef struct _mystruct
{
    int x;
    int y;
} mystruct;

void foo(mystruct *s, int count)
{
    int i;
    for(i = 0; i < count; i++)
    {
        (*(s + i)).x = 5; 
        (*(s + i)).y = 7;
    }
}

int main()
{
    mystruct ps;

    //mystruct as[1];


    foo(&ps, 1);
    //foo(as, 1);
    return 0;
}

我注意到的操作 foo 是随机的,与测试无关;它们只是为了防止编译器优化方法。

// Case 2: 1-length array
typedef struct _mystruct
{
    int x;
    int y;
} mystruct;

void foo(mystruct *s, int count)
{
    int i;
    for(i = 0; i < count; i++)
    {
        (*(s + i)).x = 5; 
        (*(s + i)).y = 7;
    }
}

int main()
{
    //mystruct ps;

    mystruct as[1];


    //foo(&ps, 1);
    foo(as, 1);
    return 0;
}

在生成的汇编文件中,在GCC上它们完全相同,而在MSVC中,字面上唯一的区别是:

  1. 注释中的变量名称(s vs as)
  2. 引用的行号(因为在每个版本中取消注释不同的行号)。

因此,可以安全地假设这两种方法是相同的。


3
2018-04-29 03:23





是。这两个选项都是堆栈分配的,并且只创建一个“实例” struct MyStruct。您的编译器应为两个选项输出相同的机器代码。看到 这个链接 (C)和 这个链接 (C ++)了解更多细节。


2
2018-04-29 03:12



操作系统询问C,链接是关于C ++和Java的。 - fluter
不完全......它解释了堆栈分配在C ++中是如何工作的以及它与Java的关系 - 即使它将C ++与Java进行比较,它也解释了堆栈分配的工作原理。我刚刚添加了另一个链接,它解释了纯C的堆栈分配。 - LordCapybara
对。看起来不错 - fluter