Arlleex 178 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба // header.h struct MY_STR { int i; }; struct MY_STR my_str; // main.c #include "header.h" // file.c #include "header.h" Почему это компилируется? Почему GCC считает строчку struct MY_STR my_str контекстно-зависимой? Почему для одного из файлов трансляции он считает эту строчку полноценным определением my_str, а для другого файла - объявлением? Перетаскивал чужой проект на ARM CLang, попался такой код. Линкер моего тулза выплюнул множественное определение my_str. Что, по мне, законно и правильно. Я в курсе, что фокус типа // in global space int i = 0; int i; тоже пройдет, и тут похожая ситуация - отличить синтаксис определения от объявления переменной структурного типа невозможно. Однако GCC "схавал", а CLang выплюнул ошибку. Как так? Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 23 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба насколько я понимаю, структура будет локальной в каждом из модулей. Вот если объявить через typedef, то другое дело Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба Только что, MrYuran сказал: насколько я понимаю, структура будет локальной в каждом из модулей. Это почему это? Обе структуры будут в глобальном пространстве, скомпилируются нормально, но на этапе линковки из одного файла у символа my_str должен будет торчать атрибут определения, а у другого - ссылки на это определение. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 24 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба 5 minutes ago, MrYuran said: насколько я понимаю, структура будет локальной в каждом из модулей. только если перед объявлением добавить static, иначе глобальная "со всеми вытекающими" Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 23 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба В 27.11.2023 в 12:44, Arlleex сказал: Это почему это? Обе структуры будут в глобальном пространстве, скомпилируются нормально, но на этапе линковки из одного файла у символа my_str должен будет торчать атрибут определения, а у другого - ссылки на это определение. Наверно, я что-то упустил. Раньше такой х-ни не было ) Двойное размещение объекта однозначно вызывало ошибку линкера. Возможно, от ключей зависит. pedantic, strict ANSI, etc Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба 38 минут назад, Arlleex сказал: Обе структуры будут в глобальном пространстве, скомпилируются нормально, но на этапе линковки из одного файла у символа my_str должен будет торчать атрибут определения, а у другого - ссылки на это определение. Может в одном из .c-файлов my_str не используется? Поэтому - выкинута компилятором и её и следов в .obj-файле не осталось. Она точно есть в обоих .obj? Если проверить их таблицы экспорта? Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба 25 минут назад, jcxz сказал: Она точно есть в обоих .obj? Если проверить их таблицы экспорта? Конкретно щас нет под рукой GCC - чуть позже гляну. Просто сам факт, что GCC это собрал. Но, опять же, если GCC рассматривает строчку struct MY_STR my_str как объявление (именно объявление, по аналогии с extern MY_STR my_str), то претензий нет. Но просто такая запись противоречит здравому смыслу, а GCC ее съедает на ура. Цитата Может в одном из .c-файлов my_str не используется? Поэтому - выкинута компилятором и её и следов в .obj-файле не осталось. Оптимизация выключена (-O0), для эксперимента в обоих модулях трансляции работаю с этой структурой - все равно компилится. GCC начинает ругаться именно если ему явно дают определение переменной: определение - это, например, объявление с инициализацией: struct MY_STR my_str = {1} Цитата Error multiple definition of `a_str' Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба 15 минут назад, Arlleex сказал: Но просто такая запись противоречит здравому смыслу, а GCC ее съедает на ура. Почему? Допустим: struct MY_STR my_str; есть в каждом .c-файле. Компилятор компилирует каждый файл по-отдельности. До сих пор всё ок? да. Но допустим: В одном из этих файлов my_str не используется (или используется static-объектом, который сам не используется и был выкинут). Или в результате фазы оптимизации использование my_str было выкинуто. Тогда в результирующем .obj не должно остаться и следа от my_str. И тогда, естественно, на этапе компоновки никаких проблем не будет. Так как и дубликатов по факту - не будет. Вроде всё логично?.. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба 2 минуты назад, jcxz сказал: Вроде всё логично?.. Логично, да. Но, ИМХО, это логично если оптимизация включена. А она выключена. И, опять же, повторюсь - переменная используется в обоих файлах явно. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба Только что, Arlleex сказал: И, опять же, повторюсь - переменная используется в обоих файлах явно. Я бы всё-таки глянул таблицы экспорта обоих .obj. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба 13 минут назад, jcxz сказал: Я бы всё-таки глянул таблицы экспорта обоих .obj. И для первого, и для второго .c-шника в таблицах символов: Цитата ... 00000002 O *COM* 00000001 a_str 00000000 g F .text.adc_GetCurrent 000000ca adc_GetCurrent ... Вычитал с законодательного стековерфлоу, что это такая фишка GCC для поддержания дурно пахнущего кода: все такие переменные (где сразу не понятно, объявление это или определение) попадают в некую секцию .common, а не в .bss или .data или куда еще, а позже на этапе линковки линкер связывает все символы с одним названием из этой секции и считает их одним символом, выделяя ей одну общую память. Забавно. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 83 27 ноября, 2023 Опубликовано 27 ноября, 2023 (изменено) · Жалоба Объявили переменную в .h без extern или const и всё проканало? Отлично, а теперь инициализуйте эту переменную там же. Уж сколько раз твердили миру - объявляйте переменные в .с файле, а в .h еёйную прописывайте как extern, если желаете сделать переменную доступной в любых файлах. Типы структур не могут быть extern, поэтому если оные нужны вовне, то объявляйте их только в. h Изменено 27 ноября, 2023 пользователем EdgeAligned Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 23 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба В 27.11.2023 в 14:05, Arlleex сказал: Забавно. Я ж говорю, давайте список ключей. Посмотрим, каких не хватает https://habr.com/ru/articles/490850/ Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба Это потому что common symbols. В "голых" Сях такое возможно, в плюсах - нет. https://binarydodo.wordpress.com/2016/05/09/investigating-linking-with-common-symbols-in-elf/ 2 Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 27 ноября, 2023 Опубликовано 27 ноября, 2023 · Жалоба Свежий gcc тоже не соберет без -fcommon - прикрыли лавочку. 1 Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться