LINUX.ORG.RU

C99 compound literals

 


0

2

Здесь: https://web.archive.org/web/20171213133641/http://www.comeaucomputing.com:80/...

Есть пример:

What Are Compound Literals?

struct xyz { int i; int j; };
// skip
void baz(struct xyz* dummy_arg) { }

int main()
{
    // skip

    // Note the literal need not always just be an array
    p = &(int){ 1 }; // ok, but be careful

    // skip

    // Pass addr of literals:
    baz(&(struct xyz){ 456, 789 });
}

Даже не пытаясь проверять, что будет в C++ и веря цитате:

https://stackoverflow.com/questions/28116467/are-compound-literals-standard-c

In C++, a compound literal designates a temporary object, which only lives until the end of its full-expression. As a result, well-defined C code that takes the address of a subobject of a compound literal can be undefined in C++.

Таки непонятно, какое будет у структуры, адрес которой передан в baz время жизни (в C)? Она будет убрана из stack'а при выходе из scope main?

★★

Последнее исправление: dissident (всего исправлений: 2)

А зачем ты пользуешь такие скользкие места? Тебе что, лень пару строчек обычной инициализации написать? Ну или я не понял суть вопроса.

deep-purple ★★★★★
()

In C++, a compound literal designates a temporary object

В C++ вообще нет compound literals

anonymous
()

well-defined C code that takes the address of a subobject of a compound literal can be undefined in C++.

Можно пример такого кода на C, который скомпилируется C++-компилятором?

anonymous
()
Ответ на: комментарий от bormant

Да и я узнал что-то новое. Например:

https://godbolt.org/z/0ME6yT

В assembler view хорошо видно, что автоматические переменные не «кладутся» на stack с помощью push, а просто пихаются в определенные места в этом stack, а потом все возращается один раз к месту где все было (pop rsp):

main:                                   # @main
        push    rbp
        mov     rbp, rsp
        xor     eax, eax
        mov     dword ptr [rbp - 4], 2
        mov     dword ptr [rbp - 32], 2
        mov     dword ptr [rbp - 56], 2
        mov     dword ptr [rbp - 80], 2
        mov     dword ptr [rbp - 104], 2
        mov     dword ptr [rbp - 108], 33
        pop     rbp
        ret

Т.е. все мои {} чтобы сделать scope и прочие компилятор тупо проигнорировал, один раз положил на stack (запомнил состояние) в начале main, потом тупо пихал, потом один раз вернул stack назад в конце main, а весь мусор там остался (более того, он туда даже не push'ился, а писался вручную).

Полезная тулза, спасибо большое!

dissident ★★
() автор топика
Ответ на: комментарий от anonymous

Там же в линке написано, что gcc поддерживает это extension, как в каком-то C90 mode с warning'ом:

https://stackoverflow.com/questions/28116467/are-compound-literals-standard-c

Если это так интересно, то попробуй сам написать и проверить, там же четыре строчки. Смысл в C++ в этих compount literals если там проще можно сделать (initializer_list что ли это будет?)

xyz x = { 2, 1 };
dissident ★★
() автор топика
Последнее исправление: dissident (всего исправлений: 2)
Ответ на: комментарий от bormant

Это понятно. ;)

Просто в институте говорили «автоматические переменные кладутся на стэк», а они туда не кладутся, а тупо «сру..я»

dissident ★★
() автор топика
Ответ на: комментарий от dissident

«автоматические переменные кладутся на стэк»

правильно говорили, кладутся, с помощью MOV
если б говорили «заталкиваются в стек» (push), был бы повод для удивления ;-)

bormant ★★★★★
()
Ответ на: комментарий от bormant

Никуда. Тут можно: https://wandbox.org/permlink/IFPQPDS8syGIuAFq. Только ничего не поменялось. Закоментирование последней строчки ведет к no warning, а откоментирование к ошибке компиляции.

Просто может быть еще так что (struct xyz){.i = 1, .j = 2} это в C++ не compund literal, а временная переменная созданная с использованием designated initializer'а и скастованная на struct xyz. Хотя не похоже {.i = 1, .j = 2 } как могло бы быть валидным без (struct xyz)? Какого типа оно бы создало это нечто, если бы вся конструкция не была compound literal, а была созданием временного нечто и кастом. Впрочем это легко проверить:

https://ideone.com/hZ8Tl3

Ну вот, не компилируется. Говорит, что создание {.i = 1, .j = 2 } это initializer_list. И кастнуть его на xyz не может. А значит конструкция (struct xyz){.i = 1, .j =2 } именно compound initializer из C, а не initializer_list кастнутый на xyz (что не компилируется, разве что reinterpret_cast там всобачить).

dissident ★★
() автор топика
Последнее исправление: dissident (всего исправлений: 2)
Ответ на: комментарий от dissident

Просто может быть еще так что (struct xyz){.i = 1, .j = 2} это в C++ не compund literal, а временная переменная созданная с использованием designated initializer'а

В ISO C++ нет designated initializer-ов.

anonymous
()
Ответ на: комментарий от bormant

Так дело в том, что в моем случае {} ничего не поменял. Никакой деструктор не был вызван у struct'а. А это ж был C выбран!

Для C++ можно перепроверить: https://godbolt.org/z/e0u8ZR. Хм тоже самое mov, call dtor, только почему-то не 4 mov, 4 call dtor, а 4 раза mov+dtor, да еще и в обратном порядке и lea еще какое-то.

Очень коунтер-интуитивно. ;)

dissident ★★
() автор топика
Ответ на: комментарий от anonymous

Ну наверное... Но компилируется же как-то большинством online компилятором (ideone, wandbox, goldbolt). Т.е. как минимум gcc и clang поддерживают. А какие еще есть компиляторы? cl.exe? zapcc? Лень проверять.

В общем я получил больше ответов, чем я ожидал, спасибо большое всем!

dissident ★★
() автор топика
Ответ на: комментарий от dissident

PS Теперь кстати понятно, почему Страуструп написал свой Cfront, так, что C++ код сначало «компилировался» в C код, а Ruby JIT компилятор делает тоже самое Ruby -> C -> Assembler. Просто всю эту муть OOP невероятно сложно выразить таким средством как Assembler.

PPS

PPPS Если бы когда нас в институте учили ассемблеру под DOS, были доступны такие интерактивные compiler explorer'ы, толку от курса было бы в Quattuortrigintillion раз больше. Так же, как если бы видео вроде этого: https://www.youtube.com/watch?v=SnQkTfSpfOU показали в третьем классе школы, то тоже понятно бы было хотя бы про физику.

Обидно, что 9 классов обучения в обычной школе (это еще в моем случае), обычно и по 12 - это абсолютная черная дыра, всасывающая время и не дающая ничего взамен.

PPPPS Сорри, опять шиза наступила, если модераторам не лень минусики ставитиь, ставьте хоть Quattuortrigintillion.

dissident ★★
() автор топика
Последнее исправление: dissident (всего исправлений: 2)
Ответ на: комментарий от dissident

Тут можно: https://wandbox.org/permlink/IFPQPDS8syGIuAFq. Только ничего не поменялось. Закоментирование последней строчки ведет к no warning, а откоментирование к ошибке компиляции.

-fpermissive ведет к предупреждению (warning), не к ошибке (error).

bormant ★★★★★
()
Ответ на: комментарий от dissident

Если бы когда нас в институте учили ассемблеру под DOS, были доступны такие интерактивные compiler explorer'ы

Это когда? В 1989 был вполне «оконный» Turbo Debugger, изучай-нехочу ;-) Правда частенько хватало просто hiew ^)

bormant ★★★★★
()
Ответ на: комментарий от dissident

И дебаггеры были, и листинг компилеры выдавали.

anonymous
()
Ответ на: комментарий от bormant

Да, я не заметил!

Start

prog.cc: In function 'int main()':
prog.cc:25:33: warning: taking address of rvalue [-fpermissive]
   25 |      printp(&(struct xyz){ 3, 4 }); // getting address of compound literal C
      |                                 ^

1 2
3 4
4 6
3 4 <- вот здесь print_p сработал как надо, несмотря на UB!

0

Finish

И даже 3,4 в конце выписались, т.е. никто еще не затер память compount literal'а, который rvalue. Спасибо!

dissident ★★
() автор топика
Ответ на: комментарий от bormant

В 2003 где-то. Значит

  • Нам, блин, не показали
  • Я, блин, тормоз (как тогда, так и сейчас)
  • AST view все равно круто
dissident ★★
() автор топика
Ответ на: комментарий от anonymous

Вроде как. В частности, оно значает, что может и заработать. Что и произшло.

dissident ★★
() автор топика

Область действия создаваемых таким образом переменных в теле функции - текущий блок.

Код

baz(&(struct xyz){ 456, 789 });
равнозначен коду
struct xyz tmp = {456, 789};
baz(&tmp);
За исключением того, что в первом случае локальной переменной не присваивается имя.

Sorcerer ★★★★★
()
Ответ на: комментарий от Sorcerer

Это в Цэ. В Це с крестом не так. Такое даже не скомпилируется без -fpermissive. Деструктор будет вызван перед первой строчкой baz.

Так следует из наших исследований выше.

То, что с -fpermissive заработало, видимо и еть тот редкий случай UB, когда чаще всего память все еще забита объектом и не успела быть использована кем-то другим, а дестрор тривиальный: того UB, где undefined = работает. Но, как понял, лучше так не делать.

Пожалуйста, поправьте меня, в случае, если я снова гоню: https://www.youtube.com/watch?v=8da1X5YfaHE

dissident ★★
() автор топика
Ответ на: комментарий от anonymous

В ISO C++ нет designated initializer-ов.

В C++20 будут, правда, таки отличные от сишных.

Laz ★★★★★
()
11 мая 2020 г.
Ответ на: комментарий от dissident

с const скомпилируется без -fpermissive

anonymous
()

В C++ вообще нет compound literals

Аноним прав. То что пишешь, это нарушение стандарта. В С++ нет compound literals. Точка. Расширения gcc это мусор. Не нужно создавать vendor lock.

fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

То что пишешь, это нарушение стандарта.

Нелепые потуги. Все, кто выше помойки - ссали на стандарт. Стандарт для птушников.

В С++ нет compound literals.

Расширения gcc это мусор.

Для птушников с помойки да - для людей - нет. Сишка - это расширения гцц, кресты - это расширения гцц.

Не нужно создавать vendor lock.

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

И никакого вендор-лока тут нет. Потому как его в принципе не существует в контексте самого свободного и попросту лучшего и единственного компилятора.

К тому же, открою тайну, но именно gnuc сделал си, сделал и c99 и с11 и C++ во многом и те же compound literals с крестовыми нюансами в крестах существуют. Причём уже в полноценном виде.

Поэтому, используя gnu - ты используешь будущие. И без этого ничего, кроме мусорного дерьма, написать нельзя. В принципе.

anonymous
()
Ответ на: комментарий от dissident

UB никакого отношения не имеет ни к работает, ни к «не работает» - это мифология созданная всякими клоунами в интернете.

В реальности UB значит лишь то, что стандарт не определяет поведение для данного случая. На то оно и ub. Клоуны сейчас породили целую секту писателей в рамках стандарта и только того, что определяет стандарт. Это концепция целиком и полностью не состоятельна.

Тот же шланг побежав за лёгким хайпом начал эту тему прорабатывать. Но как шланг. Есть некие дошколята, которые на лабе впиливают очередную оптимизацию дерьма и далее рассказывают о ней на всяких говнослётках. «оо, смотрите как мы знаем стандарт и как это не делает гцц». Уровень.

А то, что ты видишь - сделано в гцц специально, что-бы люди не путали семантику C и C++. Здесь уже говорил об этом. Время жизни подобным образом созданных объектов в си - это скоуп. А в С++ - выражение. И подобное использование во многих случаях ошибочно.

anonymous
()
Ответ на: комментарий от dissident

Смысл в C++ в этих compount literals если там проще можно сделать (initializer_list что ли это будет?)

Это даже не 5% функциональности compount literals, если мы их объединяем со списками инициализаций. Но если чисто о них, то:

Для начала, определение многих типов нативных для си ломает парсинг. char[]{2, 1} и прочее.

Но самое важное, в сишке синтаксис ещё и позволяет использовать стейтменты в скобочках, чего в крестах ни в каком виде сделать нельзя. Т.е. можно писать (struct {int x, y;}){2, 3}.

Даже struct {} x - в крестах не является выражением.

anonymous
()
Ответ на: комментарий от dissident

что автоматические переменные не «кладутся» на stack с помощью push

По определению автоматические «переменные» никуда не кладутся. Они просто автоматические. Как они реализованы - неважно.

Как вообще можно смотреть на эту убогую колозную интел-дристню я не понимаю. Какая-то бездарная паскалятская херя не читаемая. С понятиями не состоятельными в текущих реалиях, да и тогда. Понятие word сдохло ещё до своего рождения и за воротами колхозов не используется.

Само понятие как стек, push и прочее колхозное дерьмо сдохло уже давно. Целиком и полностью не состоятельно. Никто в здравом уме не будет использовать этот мусор.

Я тебе даже больше скажу - в amd64 на него попросту забили и не работает почти со всеми типами регистров.

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

один раз положил на stack (запомнил состояние) в начале main,

Повторюсь, это понятие сдохло десятки лет назад. Никакого стека уже нет. Это имя нарицательное. Никто стеком как стеком не пользуется - это просто кусок памяти.

потом тупо пихал, потом один раз вернул stack назад в конце main

Никакой стек он никуда не возвращал. Стек вернуть назад нельзя. Это всё костыли для механизма call/ret. К самое памяти отношения не имеют.

а весь мусор там остался (более того, он туда даже не push’ился, а писался вручную).

Правильно, потому что push - бездарное дерьмо колхозное, а компилятор писали не идиоты. Тоже самое всех насрать на какой-то мусор.

anonymous
()
Ответ на: комментарий от dissident

Просто всю эту муть OOP невероятно сложно выразить таким средством как Assembler.

Нет. Просто написать свой компилятор сложно. К тому же никакой ооп-мути в С++ почти нет.

PPS

Бездарный высер бездарной обезьяны с помойки.

были доступны такие интерактивные compiler explorer

Это -S с деманглером. Используется тысячи лет. Тебе просто не повезло с бездарной маздайской помойкой.

Так же, как если бы видео вроде этого: https://www.youtube.com/watch?v=SnQkTfSpfOU показали в третьем классе школы, то тоже понятно бы было хотя бы про физику.

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

Обидно, что 9 классов обучения в обычной школе (это еще в моем случае), обычно и по 12 - это абсолютная черная дыра, всасывающая время и не дающая ничего взамен.

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

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

Какой бы запарта не была, но она пытается хоть что-то реальное дать. И не упрощать всё до такого уровня, что весь основной смысл теряется.

anonymous
()
Ответ на: комментарий от dissident

Так же, как если бы видео вроде этого: https://www.youtube.com/watch?v=SnQkTfSpfOU показали в третьем классе школы, то тоже понятно бы было хотя бы про физику.

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

anonymous
()
Ответ на: комментарий от anonymous

Но самое важное, в сишке синтаксис ещё и позволяет использовать стейтменты в скобочках

Как понять что царь бредит? Он открыл рот.

Т.е. можно писать (struct {int x, y;}){2, 3}.

Что значит «т.е.»? Типа пример к предыдущему куску бреда? В школу, учить что такое стейтмент.

anonymous
()
Ответ на: комментарий от anonymous

Что значит «т.е.»? Типа пример к предыдущему куску бреда? В школу, учить что такое стейтмент.

Побежала, собака, обосновывать за кукаретинг.

anonymous
()
Ответ на: комментарий от anonymous

Побежала, собака, обосновывать за кукаретинг.

С нетерпением ждём когда вернёшься.

anonymous
()
Ответ на: комментарий от dissident

или если располагать в глобальном скоупе а не на стеке, то это будет не temporary object

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.