Да, поведение не определяется стандартом C.
Правило в C 2018 6.5 7 или C 1999 6.5 7 о том, какие типы могут использоваться для доступа к объекту, не только о том, как объекты выложены и представлены. Таким образом, предложение в вопросе «Другими словами, всегда ли элемент гибкого массива с одним элементом имеет то же смещение и размер, что и элемент массива фиксированного размера с одним элементом, учитывая, что структуры в остальном идентичны?» это неверно. Наличие одинакового смещения и размера, даже с одинаковыми определениями структуры, не делает структуры совместимыми для псевдонимов.
Разные структуры намеренно являются разными типами. Рассмотрим эти два типа:
typedef struct { double real, imaginary; } Complex;
typedef struct { double x, y; } Coordinates;
Эти структуры имеют идентичные определения (за исключением имен членов, но справедливо следующее, даже если их имена были идентичны), но они являются разными и несовместимыми типами согласно C стандарт. Это означает, что в такой подпрограмме, как:
double foo(Complex *a, Coordinates *b)
{
a->real = 3; a->imaginary = 4;
b->x = 5; b->y = 6;
return sqrt(a->real*a->real + a->imaginary*a->imaginary);
}
, компилятору разрешено оптимизировать последний оператор до return 5;
на том основании, что b->x = 5; b->y = 6;
не мог изменить a
, поскольку a
и b
не может указывать на один и тот же объект, или, если они есть, поведение b->x = 5; b->y = 6;
не определено.
Таким образом, правила C относительно псевдонимов касаются совместимых типов плюс различные исключения для конкретных случаев. , Они не в первую очередь о том, как устроены структуры.
В отличие от приведенного выше примера с различными, но идентично определенными структурами, когда у нас есть несколько указателей на один и тот же тип структуры, компилятор не может предположить, что a
и b
не являются псевдонимами (разными именами) для одного и того же объекта. В:
double foo(Complex *a, Complex *b)
{
a->real = 3; a->imaginary = 4;
b->real = 5; b->imaginary = 6;
return sqrt(a->real*a->real + a->imaginary*a->imaginary);
}
компилятор не может предположить, что возвращаемое значение равно 5, поскольку a
и b
могут указывать на один и тот же объект, и в этом случае b->real = 5; b->imaginary = 6;
изменяет содержимое a
.