Массив размера 1 по отношению к указателю на структуру

Скажем, у меня есть функция, которая берет массив структур, определенных так:

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

Ответ 1

Ответ да, они фактически одинаковы. Во-первых, массивы передаются как указатель на его первый элемент, когда они используются в аргументах функции. Фактически, все объекты в C можно рассматривать как массив одного элемента этого типа с точки зрения хранения.

Ответ 2

Они идентичны; доказательство - я скомпилировал и сохранил код сборки, сгенерированный как 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 буквально единственные отличия:

  • Имена переменных в комментариях (s vs as)
  • Номера строк, на которые ссылаются (поскольку разные версии без комментариев в каждой версии).

Поэтому можно с уверенностью предположить, что эти два метода идентичны.

Ответ 3

Да. Обе опции распределены по стекам и создают ровно один "экземпляр" struct MyStruct. Ожидается, что ваш компилятор выдаст один и тот же машинный код для обеих параметров. См. эта ссылка (C) и эта ссылка (С++) для более подробной информации.