Почему компиляторы C добавляют символы подчеркивания к внешним именам?

Я работал в C так долго, что тот факт, что компиляторы обычно добавляют символ подчеркивания к началу extern, просто понят... Однако другое SO вопрос сегодня заставил меня задаться вопросом о реальной причине добавления подчеркивания. A статья в википедии утверждает, что причина такова:

Общепринятой практикой для компиляторов C было добавление ведущего подчеркивания ко всем внешним идентификаторам внешней области видимости для предотвращения столкновений с вкладами от поддержки языка выполнения.

Я думаю, что в этом есть хотя бы ядро ​​истины, но также, похоже, на самом деле не отвечает на этот вопрос, поскольку, если подчеркивание добавляется ко всем внешним словам, это не поможет в предотвращении конфликтов.

Есть ли у кого-нибудь хорошая информация об обосновании для главного подчеркивания?

Является ли добавленная подчеркивание частью причины, по которой системный вызов Unix creat() не заканчивается знаком "e"? Я слышал, что ранние линкеры на некоторых платформах имели ограничение на 6 символов для имен. Если это так, то добавление подчеркивания к внешним именам будет казаться безумной идеей (теперь у меня есть только 5 символов, чтобы играть с...).

Ответ 1

Общепринятой практикой для компиляторов C было добавление ведущего подчеркивания ко всем внешним идентификаторам внешней области видимости для предотвращения столкновений с вкладами от поддержки языка выполнения.

Если поддержка выполнения предоставлена ​​компилятором, вы бы подумали, что было бы более целесообразно добавить символ подчеркивания к нескольким внешним идентификаторам в поддержке времени выполнения!

Когда сначала появились компиляторы C, основной альтернативой программированию на C на этих платформах было программирование на языке ассемблера, и было (и изредка) полезно связать файлы объектов, написанные на ассемблере и C. Так что действительно (IMHO), ведущее подчеркивание, добавленное к внешним идентификаторам C, состояло в том, чтобы избежать столкновений с идентификаторами в вашем собственном ассемблерном коде.

(См. также GCC asm расширение ярлыков и обратите внимание, что это добавочное подчеркивание можно рассматривать как простую форму управления именами. такие языки, как С++, используют более сложное управление именами, но это именно то, с чего оно начиналось.)

Ответ 2

если компилятор c всегда добавлял символ подчеркивания перед каждым символом, то код запуска /c -runtime (который обычно записывается в сборке) может безопасно использовать метки и символы, которые не начинаются с подчеркивания (например, символ "start" ).

даже если вы пишете функцию start() в коде c, она генерируется как _start в выводе object/asm. (обратите внимание, что в этом случае нет возможности для кода c генерировать символ, который не начинается с подчеркивания), поэтому кодер запуска не должен беспокоиться о том, чтобы изобретать неясные невероятные символы (например, $_dontuse42% $) для каждого из его/ее глобальные переменные/метки.

поэтому компоновщик не будет жаловаться на столкновение имен, а программист счастлив.:)

следующее отличие от практики компилятора, добавляющего символ подчеркивания в его выходные форматы.

Эта практика позже была кодифицирована как часть языковых стандартов C и С++, в которой использование ведущих подчеркиваний было зарезервировано для реализации.

который является соглашением, для библиотек c sytem и других системных компонентов. (и для таких вещей, как __FILE__ и т.д.).

(обратите внимание, что такой символ (ex: _time) может привести к 2 ведущим символам подчеркивания (__time) в сгенерированном выходе)

Ответ 3

Из того, что я всегда слышу, нужно избегать конфликтов имен. Не для других внешних переменных, но тем более, что при использовании библиотеки он, надеюсь, не будет конфликтовать с именами переменных кода пользователя.

Ответ 4

Основная функция - это не настоящая точка входа исполняемого файла. Некоторые статически связанные файлы имеют реальную точку входа, которая в конечном итоге вызывает main, и те статически связанные файлы имеют пространство имен, которое не начинается с подчеркивания. В моей системе, в /usr/lib, есть gcrt1.o, crt1.o и dylib1.o среди других. Каждый из них имеет функцию "запуска" без подчеркивания, которая в конечном итоге вызовет точку входа "_main". Все остальное, кроме этих файлов, имеет внешний охват. История связана с смешиванием ассемблера и C в проекте, где все C считались внешними.

Ответ 5

От Wikipedia:

Общепринятой практикой для компиляторов C было добавление ведущего подчеркивания ко всем внешним идентификаторам области видимости для предотвращения столкновений с вкладами от поддержки языка выполнения. Кроме того, когда компилятору C/С++ необходимо вводить имена во внешнюю связь как часть процесса перевода, эти имена часто отличались некоторой комбинацией нескольких ведущих или завершающих подчеркиваний.

Эта практика была позже кодифицирована как часть стандартов языка C и С++, в которой использование ведущих подчеркиваний было зарезервировано для реализации.