Страницы

Поиск по вопросам

вторник, 31 декабря 2019 г.

Как работают compound literals или внутреннее представление

#c


Вероятно некоторые знают что такое compound literals и умеют использовать это на
практике.

Однако у меня возник вопрос по внутреннему представлению этих литералов.

Ну предположим я имею такую запись: int *a = (int[]){10, 20, 30}; - таким образом
я создал и присвоил указателю адрес созданного где-то в памяти массива типа int.

Можно ли предположить что запись: int *a = (int[]){10, 20, 30}; - эквивалентна следующей
записи?

int arr[] = {10,20,30};
int *parr = arr;


По какой схеме идет присвоение адреса компаунд литерала?
    


Ответы

Ответ 1



Да, можно так считать. Аналогия из двух объявлений вами составлена корректно. Время жизни compound literal в точности определяется тем декларативным регионом, в котором он указан и совпадает с временем жизни обычной переменной того же типа, объявленной в том же контексте. То есть compound literal - это просто аналог безымянной переменной соответствующего типа с соответствующим инициализатором. Однако с этим в языке С связана одна тонкость. До появления compound literals в С не существовало отдельного вопроса времени жизни объектов, объявленных, например, в ветках if if (...) int a = 5; else int b = 42; Так как объявления в языке С не являются и никогда не являлись statements, такой код является в С некорректным. Чтобы в С создать локальный декларативный регион, допускающий объявление переменных, необходимо явно использовать {}. То есть время жизни обычных (именованных) локальных объектов в С всегда очерчено явным блоком {} и полностью объясняется через свойства блока. Однако с появлением в языке compound literals проблема времени жизни возникла вот в такой форме int *a, *b, *c; if (a = (int []) { 1, 2, 3 }) b = (int []) { 4, 5, 6 }; else c = (int []) { 7, 8, 9 }; Каково должно быть время жизни таких compound literals? Должны ли они существовать после if? До сих пор ни сам if, ни его ветки в языке С не являлись отдельными декларативными регионами - как сказано выше, в этом не было никакой необходимости. Однако после введения в язык compound literals в С99, было принято решение пойти по пути С++ и локализовать время жизни таких литералов. Теперь в С как сам if, так и его ветки, являются неявными блоками, ограничивающими время жизни созданных в них compound literals (и область видимости объявленных в них имен, см. ниже). Т.е. теперь, начиная с С99, вышеприведенный if эквивалентен int *a, *b, *c; { if (a = (int []) { 1, 2, 3 }) { b = (int []) { 4, 5, 6 }; } else { c = (int []) { 7, 8, 9 }; } } со всеми вытекающими, т.е. с "повисшими" значениями указателей. Эта же модификация относится и к другим видам statements. Это, кстати, привело к потере обратной совместимости с "классическим" С в ряде редко используемых контекстов. Например, в языке С разрешается объявлять новые типы в sizeof и в кастах. Пользуясь этой возможностью в С89/90 можно написать такой код int foo(int a) { if (a == sizeof(enum { A })) a = sizeof(enum { B }); else a = sizeof(enum { C }); return a + A + B + C; /* ОК в С89/90. Ошибка в C99 */ } После С99, из-за введения неявных блоков в if, такой код больше не компилируется.

Ответ 2



Составной литерал создает неименованный объект. Его длительность хранения зависит от того, определен он внутри функции, или вне функции. Если составной литерал объявлен вне функции, то он имеет статистическую длительность хранения, а иначе автоматическую длительность хранения. Данная запись int *a = (int[]){10, 20, 30}; эквивалентна int arr[] = {10,20,30}; int *a = arr;

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

Отправить комментарий