Использование переменной, инициализируемой в указанном инициализаторе

#c #designated-initializer

Вопрос:

Могу ли я использовать переменную, инициализируемую внутри назначенного инициализатора?

Рассмотрим следующий список:

 struct A {
    int a;
    int * const a_ptr;
};

struct A foo(int a) {
    struct A result = {
        .a = a,
        .a_ptr = amp;result.a
    };

    return resu<
}
 

demo

Могу ли я использовать result в этом обозначенном выражении инициализатора? Определено ли это поведение? Является ли этот код переносимым?

Обновить

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

 struct A {
    int a;
    int * const a_ptr;
};

void foo(int a) {
    struct A result = {
        .a = a,
        .a_ptr = amp;result.a
    };

    bar(amp;result);
}
 

Комментарии:

1. Имейте в виду, что как только значение result будет возвращено, a_ptr появится указатель на освобожденную память стека

2. Ничем не отличается void *p = amp;p; , и я полагаю, что где-то для этого есть дубликат.

3. @user16217248, вы правы, я не должен возвращать эту структуру. Это просто для иллюстрации.

4. @ivaigult ваш вопрос остается немного неясным, есть два совершенно разных фрагмента кода, так о каком из них вы на самом деле спрашиваете?

5. @Jabberwocky, более поздний. Я сохранил старую версию просто для того, чтобы быть вежливым с людьми, опубликовавшими первые комментарии по этому поводу, поэтому я не аннулирую их комментарии. Вопрос заключается исключительно в синтаксической конструкции и порядке инициализации, речь не идет о UB, который я представил в первой версии.

Ответ №1:

Инициализация сама по себе прекрасна.

В момент result объявления его адрес (как и адреса его полей) является постоянным. Поэтому его безопасно использовать amp;result.a в инициализаторе result .

Однако проблема заключается в том, что вы возвращаете копию этой структуры. Эта копия содержит адрес локальной переменной, которая больше не существует, поэтому попытка использовать значение a_ptr члена возвращаемой структуры вызовет неопределенное поведение.

Комментарии:

1. Но можно ли использовать значение ранее инициализированного поля? struct {int a, b;} myStruct = {.a - 10, .b = a};

2. @user16217248 Я не думаю, что порядок инициализации четко определен.

3. @user16217248 Это совсем другой случай. Порядок инициализации не указан, поэтому нет никакой гарантии, что .a он будет установлен раньше .b .

4. @dbush Я думаю, что это не совсем так. Порядок определен в пункте 6.7.9 пункта 11. «Напротив, обозначение заставляет следующий инициализатор начинать инициализацию подобъекта, описанного обозначающим. Затем инициализация продолжается по порядку, начиная со следующего подобъекта после того, который описан указателем.»

5. @ivaigult Это предложение указывает вам, с какими подобъектами связан инициализатор, а не порядок оценки. p23 говорит об оценке: «Оценки выражений списка инициализации неопределенно упорядочены относительно друг друга, и, следовательно, порядок, в котором возникают какие-либо побочные эффекты, не указан».

Ответ №2:

Вопрос полностью изменился, вот мой новый ответ:

Ваш код в порядке, вы можете проверить это, он не будет утверждаться ни на одной платформе.

Вы передаете указатель на локальную переменную result bar кому . В bar этой локальной переменной все еще существуют p точки, указывающие на эту переменную (результат). Поэтому a_ptr все еще указывает на result.a .

Но мне просто интересно, чего вы здесь пытаетесь достичь.

 #include <assert.h>

struct A {
  int a;
  int* const a_ptr;
};    

void bar(struct A *p)
{
  assert(p->a_ptr == amp;p->a);
}    

void foo(int a) {
  struct A result = {
      .a = a,
      .a_ptr = amp;result.a
  };

  bar(amp;result);
}

int main()
{
  foo(2);
}
 

кстати:

  struct A result = {
      .a = a,
      .a_ptr = amp;result.a
  };
 

эквивалентно этому:

   struct A resu<  
  result.a = a;
  result.a_ptr = amp;result.a;
 

но для последнего вам нужно было бы объявить int* a_ptr; вместо int* const a_ptr; этого .