Вероятно некоторые знают что такое compound literals и умеют использовать это на практике.
Однако у меня возник вопрос по внутреннему представлению этих литералов.
Ну предположим я имею такую запись: int *a = (int[]){10, 20, 30}; - таким образом я создал и присвоил указателю адрес созданного где-то в памяти массива типа int.
Можно ли предположить что запись: int *a = (int[]){10, 20, 30}; - эквивалентна следующей записи?
int arr[] = {10,20,30};
int *parr = arr;
По какой схеме идет присвоение адреса компаунд литерала?
Ответ
Да, можно так считать. Аналогия из двух объявлений вами составлена корректно.
Время жизни 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, такой код больше не компилируется.
Комментариев нет:
Отправить комментарий