Подтвердить что ты не робот

Возврат локальной частично инициализированной структуры из функции и поведения undefined

(Посредством частичной инициализации я имею в виду, что она определена как неинициализированная, и один из ее членов задан для некоторого допустимого значения, но не для всех из них. А по локальному я имею в виду определение с автоматической продолжительностью хранения. Этот вопрос говорит только об этом.)

Используя автоматическую неинициализированную переменную, которая может быть определена с регистром, поскольку поведение rvalue является undefined. Структуры могут быть определены с помощью спецификатора класса хранения хранилища.

6.3.2.1

  1. Если lvalue обозначает объект с автоматическим временем хранения, который мог бы быть объявлен с классом хранения регистров (никогда не был принят его адрес), и этот объект не инициализируется (не объявляется с инициализатором, и никакое присвоение ему не было выполняется до использования), поведение undefined.

Обратите внимание, что он конкретно говорит, что и никаких присвоений ему не было выполнено.

Кроме того, мы знаем, что структура не может быть значением ловушки:

6.2.6.1.

  1. Значение структуры или объекта объединения никогда не является ловушным представлением, хотя значение члена структуры или объекта объединения может быть представление ловушки

Таким образом, возвращение неинициализированной структуры явно undefined.

Заявление: определяется неинициализированная структура, которая имеет один из ее членов, назначенных с допустимым значением.

Пример для более простого понимания:

struct test
{
    int a;
    int b;
};

struct test Get( void )
{
    struct test g;
    g.a = 123;
    return g;
}

{
    struct test t = Get();
}

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

Правильно ли мое утверждение?

4b9b3361

Ответ 1

Помимо детали возврата значения из функции, это как раз предмет Отчет о дефектах 222, представленный в 2000 году Клайвом Пером, и резолюция что DR, похоже, довольно четко отвечает на вопрос: возврат частично-неинициализированного struct является корректным (хотя значения неинициализированных членов не могут использоваться.)

Разрешение DR подтвердило, что объекты struct и union не имеют ловушечных представлений (которые были явно добавлены в раздел 6.2.6.1/6). Следовательно, однонаправленное копирование не может использоваться в архитектуре, в которой отдельные члены могут попасть в ловушку. Хотя, предположительно, для синтаксического выражения, к стандарту не было добавлено явного утверждения об этом эффекте, сноска 42 (теперь сноска 51), которая ранее упоминала о возможности копирования по одному члену, была заменена гораздо более слабым утверждением, указывающим, что биты заполнения не должны скопированы.

Протоколы совещания WG14 (Торонто, октябрь 2000 г.) понятны (выделено мной):

DR222 - Частично инициализированные структуры

Этот DR задает вопрос о целесообразности назначения structопределяется, когда источником присвоения является struct, некоторые из которых членам не дали значения. Был достигнут консенсус в отношении того, что это должен быть четко определен из-за общего использования, включая стандартную структуру struct tm. Был также достигнут консенсус, что если назначение с некоторыми членами, неинициализированными (и, возможно, с значение ловушки) было четко определено, в требуя, чтобы по крайней мере один член получил должное значение.
Поэтому понятие о том, что значение a struct или union в целом может имеют значение ловушки.

Интересно отметить, что в вышеуказанные минуты комитет считал, что даже не нужно, чтобы одному члену struct была предоставлена ​​ценность. Однако это требование впоследствии было восстановлено в некоторых случаях с разрешением DR338 (см. Ниже).

Вкратце:

  • Если автоматический агрегатный объект был хотя бы частично инициализирован или если его адрес был взят (тем самым он не подходит для объявления register в соответствии с разделом 6.3.2.1/2), тогда lvalue- to-rvalue для этого объекта хорошо определен.

  • Такой объект может быть назначен другому агрегированному объекту того же типа, возможно, после его возврата из функции, без вызова поведения undefined.

  • Чтение неинициализированных членов в копии является либо undefined, либо неопределенным, в зависимости от того, возможны ли представления ловушки. (Чтение указателя на неподписанный тип узкого символа не может, например, захватить ловушку.) Но если вы напишете член перед его чтением, вы в порядке.

Я не верю, что существует теоретическая разница между назначением объектов union и struct. Очевидно, что union не может быть скопирован членом членом (что бы это означало) и что тот факт, что какой-то неактивный член имеет ловушечное представление, не имеет значения, даже если этот элемент не сглажен ни одним другим элементом. Нет очевидной причины, почему struct должен отличаться.

Наконец, что касается исключения из раздела 6.3.2.1/2: это было добавлено в результате разрешения DR 338. Суть этого DR заключается в том, что некоторое аппаратное обеспечение (IA64) может заманить использование неинициализированного значения в регистр. C99 не допускает представления ловушек для неподписанных символов. Таким образом, на таком оборудовании может оказаться невозможным поддерживать автоматическую переменную в регистре без "ненужного" инициализации регистра.

Резолюция DR 338 специально отмечает как поведение undefined использование неинициализированных значений в автоматических переменных, которые, возможно, могут храниться в регистрах (т.е. те, адрес которых никогда не был взят, как бы объявлен register), таким образом позволяя компилятору сохранить автоматический unsigned char в регистре, не беспокоясь о предыдущем содержимом этого регистра.

Как побочный эффект DR 338, кажется, что полностью неинициализированный автоматический struct, адрес которого никогда не был принят, не может подвергаться преобразованию lvalue-to-rvalue. Я не знаю, был ли этот побочный эффект полностью рассмотрен в резолюции DR 338, но он не применяется в случае частично инициализированного struct, как в этом вопросе.

Ответ 2

Ваше утверждение относительно 6.3.2.1 является правильным, если объект, присвоенный lvalue, не инициализирован, то поведение undefined.

Итак, тогда возникает вопрос, следует ли рассматривать вашу структуру как неинициализированную или нет. Вы назначаете значение одному из членов, поэтому было назначено задание. Согласно приведенному в 6.3.2.1, это означает, что вы не можете рассматривать структуру целиком как неинициализированную. Этот конкретный элемент явно инициализирован, хотя другие члены не являются.

Существует, однако, еще один случай поведения undefined, и это при хранении представления ловушки в lvalue:

6.2.6.1/5
Определенные представления объектов не должны представлять значение тип объекта. Если хранимое значение объекта имеет такое значение представления и считывается выражением lvalue, которое не имеет тип символа, поведение undefined. Если такое представление созданный побочным эффектом, который изменяет всю или любую часть объекта выражением lvalue, которое не имеет типа символа, поведение undefined.50). Такое представление называется ловушкой представление.

В тексте, приведенном в 6.2.6.1/6, говорится, что сама структура не может быть ловушечным представлением, хотя отдельные ее элементы могут быть ловушками. Если они есть, то назначение будет undefined по сравнению с приведенным выше.

Но обратите внимание, что "может быть ловушкой". Не исключено, что они являются ловушками, потому что они имеют неопределенные значения. Взгляните на основы:

6.7.9/10
Если объект с автоматической продолжительностью хранения не инициализирован явно, его значение неопределенно.

и

3.19.2/1
неопределенное значение
либо неопределенное значение, либо представление ловушки

Использование переменной с неопределенным значением - это только поведение undefined в случае, если значение представляет собой ловушечное представление.

Независимо от того, будут ли неинициализированные переменные-члены вашей структуры содержать неопределенные значения или представления ловушек, это поведение, определяемое реализацией.

Если переменная с неопределенным значением просто имеет неопределенное значение, то 6.2.6.1/5 не применяется и поведение undefined отсутствует.

Заключение: если в реализации указано, что любое неопределенное значение для любого из элементов структуры является ловушечным представлением, поведение undefined. В противном случае поведение просто определяется/неопределено, неинициализированные члены будут содержать неопределенные значения.