Объяснение правила времени жизни в стандарте C - PullRequest
6 голосов
/ 13 июня 2019

Я пишу компилятор C (с llvm в качестве бэк-энда) для практики, и за правилами следует стандарт C11 §6.2.4 .

При прохождениичасть «Длительность хранения объектов», один случай меня смутил:

¶8 Не-lvalue выражение со структурой или типом объединения, где структура или объединение содержит член с типом массива (включая,рекурсивно (члены всех содержащихся структур и объединений) относится к объекту с автоматическим хранением и временным временем жизни.Его время жизни начинается, когда выражение вычисляется, и его начальное значение является значением выражения.Его время жизни заканчивается, когда заканчивается оценка содержащего полного выражения или полного декларатора.Любая попытка изменить объект с временным временем жизни приводит к неопределенному поведению.

Я не могу себе представить, о чем говорит этот случай, особенно часть элемента массива ( Поскольку оба ненулевых значения с временнымвремя жизни, имеет ли структура с членом массива какие-либо различия с обычным ненулевым значением? ) Может кто-нибудь дать мне пример кода, чтобы проиллюстрировать это?

Ответы [ 3 ]

5 голосов
/ 13 июня 2019

Временные значения без массивов в них не должны ссылаться на объекты с автоматической (или вообще любой) длительностью хранения. Массивы являются особыми, потому что преобразование массива в указатель - единственная полезная операция, которую можно выполнить с массивом, неявно требует, чтобы у него был адрес, поэтому компилятор должен выделить для него память (и, следовательно, неявно для всего объекта, который содержит его). Значения без массивов не имеют адресов.

struct a { int x; };
struct b { int y[2]; };
void foo(int*);
struct a one();
struct b two();

foo(&one().x); // not legal
foo(two().y); // legal, y has an address
1 голос
/ 13 июня 2019
struct Foo {
  int i[1]; //structure contains a member with array type
};

struct Foo getFoo() {
  struct Foo foo;
  foo.i[0] = 1;
  return foo;
}

void test() {
  // getFoo().i life time begin;
  int *p = getFoo().i; //A non-lvalue expression with structure type
  // getFoo().i is automatic storage duration and temporary lifetime
  // getFoo().i life time end;
  assert(*p == 1); // Any attempt to modify an object with temporary lifetime results in undefined behavior.
}
0 голосов
/ 13 июня 2019

Проблема обсуждается (с примерами) в SEI CERT C Coding Standard. Действительно, это очень крайний случай языка.

Я не копирую код здесь - достаточно ссылки на ссылку.

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

Например, он действителен в C11, но недействителен в C99:

++(st().arr)[0]  // try to mutate before the full expression ends.
x=st().arr       // access array from a temporary returned structure
                 // before the sequence point at the end of full expression 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...