Временные объекты в C - PullRequest
       2

Временные объекты в C

6 голосов
/ 28 апреля 2019

В C11 был определен термин temporary lifetime:

C11 6.2.4p8: выражение без значения со структурой или типом объединения, где структура или объединение содержит член с типом массива (включая, рекурсивно, члены всех содержащихся структур и объединений) относится к объекту с автоматическим хранением и временным временем жизни.36) Время его жизни начинается, когда выражение вычисляется, и его начальное значение является значением выражения.Его время жизни заканчивается, когда заканчивается оценка содержащего полного выражения или полного декларатора.Любая попытка изменить объект с временным временем жизни приводит к неопределенному поведению.

Мне интересно, почему это относится только к значениям структуры или типа объединения, которые имеют член массива типа.Что такого особенного в массивах?

struct x { int xx; };
struct y { int yy[1]; };

(struct x)   { 42 };    // *not* a temporary object
(struct y) { { 42 } };  // a temporary object

Почему первый объект не должен быть временным, в то время как второй является?

Ответы [ 2 ]

1 голос
/ 28 апреля 2019

Причина, по которой ограничение применяется только к временным объектам, которые содержат массивы, заключается в том, что ограничение относится только к временным объектам, которые содержат массивы - когда у вас есть неназванный объект без значения, который НЕ содержит массив, вы не можете получить адрес от объекта; использование & явно запрещено. Однако, когда объект содержит массив и вы обращаетесь к этому массиву по имени, вы неявно получаете адрес первого элемента массива. До C11 попытка сделать НИЧЕГО с этим указателем была неопределенным поведением. С C11 вы можете теперь использовать объект (и указатель), вы просто не можете его изменить.

0 голосов
/ 28 апреля 2019

Я не совсем уверен в этом, но вот что я понимаю из чтения EXP35-C. Не изменяйте объекты с временным временем жизни несколько раз. Это не очень хороший language-lawyer ответ, но я попытаюсь объяснить его в более простых терминах.

Обычно функция C не может вернуть массив. Тем не менее, вы (пытаетесь) обойти это, прикрепив массив в структуре и вернув его. Рассмотрим пример кода:

#include <stdio.h>

struct X { char a[8]; };

struct X salutation(void) {
  struct X result = { "Hello" };
  return result;
}

struct X addressee(void) {
  struct X result = { "world" };
  return result;
}

int main(void) {
  printf("%s, %s!\n", salutation().a, addressee().a);
  return 0;
}

В C99 эта программа вызывала неопределенное поведение. Вы не можете даже получить доступ к массиву внутри структуры. Причина в том, что время жизни массива заканчивается, когда функция с локальной переменной возвращается.

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

Из-за этой тонкой разницы правило EXP35-C также рекомендует не делать этого. Вместо этого сохраните результат, содержащий массив, в локальную переменную:

#include <stdio.h>

struct X { char a[8]; };

struct X salutation(void) {
  struct X result = { "Hello" };
  return result;
}

struct X addressee(void) {
  struct X result = { "world" };
  return result;
}

int main(void) {
  struct X my_salutation = salutation();
  struct X my_addressee = addressee();

  printf("%s, %s!\n", my_salutation.a, my_addressee.a);
  return 0;
}
...