clang или gcc кто прав в Си?
Исходный код:
Компилировать: gcc a.c b.c -o a.out или clang a.c b.c -o a.out
Начиная с GCC версии 10 стало:
В clang нет ошибок, во всех прошлых версиях gcc, я проверял начиная с gcc 5.4 до gcc9, тоже нет обшибок.
Очевидный фикс это добавить typedef для структуры в c.h, просто интересно кто прав в этой ситуации.
получается что clang не соблюдает стандартов?
gcc просто стал более строгим по умолчанию. Все правы, виноватых нет ::) Юзать кланг смысла нема, по скоростям близко, бинарники жирнее копирует фичи gcc и всё такое прочее. Юзай gcc и не парься, а только в особых случаях Android NDK где шланг прибили гвоздями юзай его.
бОльшая часть инклюдов в /usr/include именно так и сделана.
Твоя проблема в том, что:
определяет глобальную переменную с именем struct_h в дополнение к самой структуре.
И ошибки не будет.
А твой фикс с typedef:
делает struct_h не переменной, а typedef .
Ты забыл include guards.
facepalm. static напиши. повторное определение не потому что структура struct_h дважды определена, а потому переменная struct_h два раза включена в .c файлы. у тебя ошибка линковки, а не компиляции.
ты так набросить чтоли решил?
И чего все так #pragma once не любят?
Нестандарт, но не умеющих компиляторов ещё не встречал (хотя GCC с какого-то бодуна объявляли одно время устаревшей). Работает, если не заниматься извращениями, хорошо, а выглядит поаккуратней, чем «оборачивания» в include guards.
Половина отписавшихся так и не поняли, что это ошибка на этапе линковки, а не компиляции.
получается что clang не соблюдает стандартов?
Соблюдает. Тут неопределённое поведение. Оно не обязано быть диагностированным.
gcc просто стал более строгим по умолчанию.
В каком смысле «более строгим»?
Да какбы коню ясно, но это как-то в корне меняет суть вопроса ТС?
Ну теперь включили -fno-common по умолчанию и GCC резервирует глобалы не COMMON, позволяя компоновщику самому решать куда их пихать: в .bss или .data, а напрямую в .bss, что компоновщик уже не соберёт. И это работает, пока не инициализируешь этот глобал в двух юнитах сразу. При неоднократной инициализации также не соберётся — будет multiple definition of struct_h .
Но ТС-у это вряд-ли сильно интересно.
В этой ситуации ты саморучно, и того не подозревая, создаёшь глобальную переменную struct_h типа struct struct_h. Все, что тебе надо, это заменить > struct_h; на >; . И добавить гарды во все хидеры, но это не связанная проблема.
Спасибо за пояснение. Вот этот проект весь пронизан подобными ситуациями со структурами и переменными:
Начал было всё вычищать, но там много времени надо потратить.
Получается проще сделать так:
Чтобы ошибки линковки исчезли.
Ну теперь включили -fno-common по умолчанию
Кстати, почему в GCC и в новой версии Clang этот флаг активировали по-умолчанию? Чем руководствовались? Может кто развёрнуто объяснить?
Bugzilla GCC — 85678, например.
Ну, если оно собиралось и работало, то да — проще переключить флаг обратно.
У Clang «автоматический constexpr» круче, и ошибки находит лучше.
И чего все так #pragma once не любят?
Не все. Я про него вообще не знал, пока не показал кусочек кода чуваку, работающему в яндексе. После чего был поднят на смех.
Ну как же: встроенный language server, более разумные сообщения об ошибках (особенно в темплейтах), гораздо меньшее количество танцев с бубном для кросскомпиляции. Не говоря уже о том, что будет, если вдруг возникнет задача модифицировать сам компилятор или писать программу, в которую нужно встроить парсер C++.
более разумные сообщения об ошибках (особенно в темплейтах)
Нет, в gcc лучше.
В clang сообщения короче, но ничего непонятно. gcc не убирает контекст, там нужно лишь прочитать ошибку и понятно в чём она.
Clang vs Gcc: две компиляторные системы в одном дистрибутиве
По моим представлениям длительное время clang/llvm использовал
из компилятора gcc (на стадии dragonegg еще и фронтенд языка C/C++). Но при этом разработчики clang/llvm последовательно двигаются к достижению полной замкнутости. Похоже они достигли независимости по binutils, libc++. Активно пилят свою версию libc. Что касается взгляда со стороны, то между разработчиками gcc и clang нет стремления к поддержанию совместимости своих систем (стандарт C/C++ не гарантирует совместимости бинарников библиотек и/или хедеров). Соответственно возникает вопрос, а что будет с linux/unix-дистрибутивами после достижения полной независимости в clang/llvm от gcc (glibc по сути последний мостик)?
Уточню суть вопроса. Пусть есть дистрибутив (Ubuntu/Mint/…), который собран gcc. Можно закачивать пакеты, собранные разработчиками дистрибутива. Допустим есть приложение X, которое собирается с помощью clang. Приложение X зависит от библиотеки Y (и еще большего количества других библиотек). Все требуемые библиотеки уже установлены в дистрибутиве, но собраны с помощью gcc. При сборке X clang соберет ее с хедерами и слинкует ее с libc/libstdc++. Если X будет слинкована с установленной Y, то при запуске X, получается, что X должна использовать func (какую-нибудь fopen или std::vector()) из libc/libstdc++, а Y должна использовать func из glibc/libstdc++. Но по текущим правилам линковки глобальный символ func будет взят из одной библиотеки. Но независимо развиваемые библиотеки не будут совместимы и взаимозаменяемыми. Более сложная ситуация, когда хедеры Y будут просто по-разному скомпилированы clang и gcc, в том числе из-за разных хедеров libc++ и libstdc++.
Тогда получается, что для компиляции X нужна Y также собранная с помощью clang? В отдельных случаях можно заморочиться и собрать Y в ручную. Но собрать все такие библиотеки — это по сути сделать кусочек дистрибутива, собранного clang’ом (а у некоторых проектов системы сборки могут быть сложными). Поэтому хотелось бы точно также скачать пакет с собранной версией Y. Значит ли это, что дистрибутив должен теперь быть собран в двух экземплярах — каждый пакет с помощью gcc и каждый пакет с помощью clang?
Уже давно около 70% пакетов в дебиане собраны шлангом. Есть дистр позиционирующий свою модность. Они там заявляют, что программы быстрее работают если их шлангом компилять. В Gentoo можно собирать любым компилятором. И если что-то дает лучший эффект то и используется. Но некоторые программы требуют всю цепочку собрать одним компилятором и смешивание отдельный вопрос и самостоятельно можо указать в файлике какие пакеты чем собраны.
Ради интереса пробовал пилить сборку Linux на базе llvm / llc / lld, compiler-rt, musl — всё вполне прекрасно работает
gcc + glibc иногда криво, либо жирно собирают статически линкованные бинарники
Щас с приходом докера интерес к статической линковке возрос
Что касается взгляда со стороны, то между разработчиками gcc и clang нет стремления к поддержанию совместимости своих систем (стандарт C/C++ не гарантирует совместимости бинарников библиотек и/или хедеров).
Как это нет? Оба компилятора реализуют Intel Itanium ABI и динамическая библиотека на C++, собранная одним компилятором, должна работать в программе, собранной другим компилятором. У gcc и clang по большей части совместимы флаги командной строки так что они взаимозаменяемы. Например в Haiku (там значительная часть API на C++), собранной с помощью clang/lld, работают бинарники, собранные с помощью gcc.
От gcc нужны были только объектники с инициализацией/финализацией, не? Просто чтобы не плодить сущности.
Которые почему-то считаются частью пакета компилятора, а не libc.
От gcc нужны были только объектники с инициализацией/финализацией, не?
В библиотеках clang/llvm они тоже есть. Инфраструктура LLVM полностью самодостаточна.
Я знаю. А зачем он при запуске делает автодетект пути, по которому установлен gcc?
Я так предполагаю, в gcc-based дистрибутивах его собирают не в полном комплекте?
А зачем он при запуске делает автодетект пути, по которому установлен gcc?
Вопрос к авторам дистрибутива?
Увидел файлы с соответствующими названиями в пакете compiler-rt.
Тогда хз, зачем он продолжает искать путь с файлами gcc.
Буду за компом, гляну сорцы.
я видел как программы от него работают медленнее
тем более в дебиане вечно пропихивают всякое говно, вроде как когда-то libav вместо ffmpeg
А можно тему со смешиванием раскрыть подробнее? О каком файлике идет речь? Есть ли штатный способ одновременно держать две библиотеки, собранные gcc и clang? Как переход clang на libc (а значит перерубание последнего каната, связывающих их с gcc) может повлиять на экосистему дистрибутивов? Про 70% не знал — это точно?
Как это нет? Оба компилятора реализуют Intel Itanium ABI
В основу реализации EH действительно взята идея ZeroCost от Itanium’а, но кто-то внес свои «расширения», а другие — свои и вот библиотеки libc++ и libstdc++ из-за пары «всего лишь» каких-то деталей стали не совместимы
динамическая библиотека на C++, собранная одним компилятором, должна работать в программе, собранной другим компилятором.
А с чего это вдруг? Стандартные библиотеки могут иметь различные хедеры. В итоге библиотека собрана с одними стандартными хедерами, приложение — с другими. А при запуске по правилам линковки одна стандартная библиотека «заборет» другую. В итоге либо приложение, либо динамическая библиотека будут работать не с той стандартной библиотекой, с которой компилировались. А там еще какой-нибудь std::vector по разному реализован и пошло поехало и вот уже хедера самой динамической библиотеки по-разному компилируются.
У gcc и clang по большей части совместимы флаги командной строки так что они взаимозаменяемы.
Есть много флагов, которые есть только у gcc, и наоборот. Но речь не по флаги. Речь по то, что получается на выходе из компиляторов, и насколько совместимы результаты, а не про то, что проекты можно (целиком) компилировать gcc или (целиком) clang.
Например, несколько лет назад разработчики gcc взяли и просто так поменяли алгоритм манглирования. У разработчиков clang на полгода перестал работать компилятор. Вряд ли они этому обрадовались, но делать нечего из-за технологической зависимости пришлось опять подстраиваться под gcc. А при полной независимости ни под кого они подстраиваются уже не будут.
С другой стороны llvm создает ассемблер, который в общем случае gas не может ассемблировать (если не использовать gas для asm-файлов из под llvm, то и ничего страшного, но это к вопросу о стремлении к совместимости, которая не на входе, а на выходе).
Например в Haiku (там значительная часть API на C++), собранной с помощью clang/lld, работают бинарники, собранные с помощью gcc.
Ну сейчас свезло, а что будет, когда clang полностью перейдет на libc/libc++? Про это собственно и речь.
А при запуске по правилам линковки одна стандартная библиотека «заборет» другую.
Есть symbol versioning который позволяет в том числе импортировать символ из конкретной библиотеки даже если символ с таким же именем есть в другой загруженной библиотеке.
Например, несколько лет назад разработчики gcc взяли и просто так поменяли алгоритм манглирования.
Вы про переход GCC 3 со своего манглирования на Itanium ABI или что-то другое? Если про это, что это было давно (2001 год) и вряд ли что либо серьёзно поменяется.
а что будет, когда clang полностью перейдет на libc/libc++
Ничего не будет. В Haiku std::vector, string и т.п. в публичных API не используются, их можно использовать только во внутренней реализации.
По моим представлениям длительное время clang/llvm использовал binutils glibc/libstdc++ из компилятора gcc
Шта? binutils это отдельный проект, а glibc даже не плюсовая библиотека.
Тогда получается, что для компиляции X нужна Y также собранная с помощью clang?
Главное — не компилятор, а плюсовый рантайм. Конечно же код собранный с libstdc++ и libc++ несовместим.
Значит ли это, что дистрибутив должен теперь быть собран в двух экземплярах — каждый пакет с помощью gcc и каждый пакет с помощью clang?
Нет, это значит что X которая собирается только clang’ом не будет опакечена в этом дистрибутиве.
и динамическая библиотека на C++, собранная одним компилятором, должна работать в программе, собранной другим компилятором
И как, на бзде сможешь повторить хотя бы сабж из топика? С нотариально заверенным видосом, конечно же.
Э, без понятия как я оказался в этой теме. В любом случае, вопрос к этому.