Перейти к содержанию
    

Почему для GCC следующий код в полном порядке?

// 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 выплюнул ошибку. Как так?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

насколько я понимаю, структура будет локальной в каждом из модулей.

Вот если объявить через typedef, то другое дело

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Только что, MrYuran сказал:

насколько я понимаю, структура будет локальной в каждом из модулей.

Это почему это? Обе структуры будут в глобальном пространстве, скомпилируются нормально, но на этапе линковки из одного файла у символа my_str должен будет торчать атрибут определения, а у другого - ссылки на это определение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 minutes ago, MrYuran said:

насколько я понимаю, структура будет локальной в каждом из модулей.

только если перед объявлением добавить static, иначе глобальная "со всеми вытекающими"

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 27.11.2023 в 12:44, Arlleex сказал:

Это почему это? Обе структуры будут в глобальном пространстве, скомпилируются нормально, но на этапе линковки из одного файла у символа my_str должен будет торчать атрибут определения, а у другого - ссылки на это определение.

Наверно, я что-то упустил. Раньше такой х-ни не было )

Двойное размещение объекта однозначно вызывало ошибку линкера. Возможно, от ключей зависит. pedantic, strict ANSI, etc

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

38 минут назад, Arlleex сказал:

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

Может в одном из .c-файлов my_str не используется? Поэтому - выкинута компилятором и её и следов в .obj-файле не осталось.

Она точно есть в обоих .obj? Если проверить их таблицы экспорта?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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'

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 минут назад, Arlleex сказал:

Но просто такая запись противоречит здравому смыслу, а GCC ее съедает на ура.

Почему?

Допустим: struct MY_STR my_str; есть в каждом .c-файле. Компилятор компилирует каждый файл по-отдельности. До сих пор всё ок? да.

Но допустим: В одном из этих файлов my_str не используется (или используется static-объектом, который сам не используется и был выкинут). Или в результате фазы оптимизации использование my_str было выкинуто. Тогда в результирующем .obj не должно остаться и следа от my_str. И тогда, естественно, на этапе компоновки никаких проблем не будет. Так как и дубликатов по факту - не будет.

Вроде всё логично?..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 минуты назад, jcxz сказал:

Вроде всё логично?..

Логично, да. Но, ИМХО, это логично если оптимизация включена. А она выключена.

И, опять же, повторюсь - переменная используется в обоих файлах явно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Только что, Arlleex сказал:

И, опять же, повторюсь - переменная используется в обоих файлах явно.

Я бы всё-таки глянул таблицы экспорта обоих .obj.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 минут назад, jcxz сказал:

Я бы всё-таки глянул таблицы экспорта обоих .obj.

И для первого, и для второго .c-шника в таблицах символов:

Цитата

...

00000002       O *COM*  00000001 a_str
00000000 g     F .text.adc_GetCurrent   000000ca adc_GetCurrent

...


Вычитал с законодательного стековерфлоу, что это такая фишка GCC для поддержания дурно пахнущего кода: все такие переменные (где сразу не понятно, объявление это или определение) попадают в некую секцию .common, а не в .bss или .data или куда еще, а позже на этапе линковки линкер связывает все символы с одним названием из этой секции и считает их одним символом, выделяя ей одну общую память. Забавно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Объявили переменную в .h без extern или const и всё проканало? Отлично, а теперь инициализуйте эту переменную там же. 

Уж сколько раз твердили миру - объявляйте переменные в .с файле, а в .h еёйную прописывайте как extern, если желаете сделать переменную доступной в любых файлах. 

Типы структур не могут быть extern, поэтому если оные нужны вовне, то объявляйте их только в. h

Изменено пользователем EdgeAligned

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 27.11.2023 в 14:05, Arlleex сказал:

Забавно.

Я ж говорю, давайте список ключей. Посмотрим, каких не хватает

https://habr.com/ru/articles/490850/

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это потому что common symbols. В "голых" Сях такое возможно, в плюсах - нет. https://binarydodo.wordpress.com/2016/05/09/investigating-linking-with-common-symbols-in-elf/

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гость
Эта тема закрыта для публикации ответов.
×
×
  • Создать...