Почему компиляторы C добавляют подчеркивания к внешним именам?
Я работал в C так долго, что тот факт, что компиляторы обычно добавляют подчеркивание в начале extern
только что поняли... Тем не менее, еще один вопрос сегодня заставил меня задуматься об истинной причине, почему подчеркивание добавлено. Статья в Википедии утверждает, что причина:
Для компиляторов Си было обычной практикой ставить перед всеми внешними идентификаторами программ области видимости подчеркивание, чтобы предотвратить конфликты с вкладами из языковой поддержки во время выполнения.
Я думаю, что по крайней мере в этом есть доля правды, но, похоже, на самом деле нет ответа на этот вопрос, поскольку добавление подчеркивания ко всем внешним элементам не сильно поможет в предотвращении столкновений.
Есть ли у кого-нибудь хорошая информация об обосновании ведущих подчеркивания?
Является ли добавленное подчеркивание одной из причин того, что Unix creat()
системный вызов не заканчивается на "е"? Я слышал, что ранние компоновщики на некоторых платформах имели ограничение в 6 символов для имен. Если это так, то добавление подчеркивания к внешним именам может показаться совершенно безумной идеей (теперь у меня есть только 5 символов для игры...).
5 ответов
Для компиляторов Си было обычной практикой ставить перед всеми внешними идентификаторами программы области видимости подчеркивание, чтобы предотвратить конфликты с вкладами языковой поддержки времени выполнения.
Если поддержка во время выполнения обеспечивается компилятором, вы могли бы подумать, что вместо этого стоит добавить подчеркивание к нескольким внешним идентификаторам в поддержке времени выполнения!
Когда впервые появились компиляторы C, основной альтернативой программированию на C на этих платформах было программирование на языке ассемблера, и было (и иногда до сих пор) полезно связывать воедино объектные файлы, написанные на ассемблере и C. Так что действительно (ИМХО) ведущий Подчеркивание добавлено к внешним идентификаторам C, чтобы избежать столкновений с идентификаторами в вашем собственном коде сборки.
(Смотрите также GCC asm
расширение метки; и обратите внимание, что это предварительное подчеркивание можно считать простой формой искажения имени. Более сложные языки, такие как C++, используют более сложное искажение имен, но это то, с чего все началось.)
Если компилятор c всегда ставит перед каждым символом знак подчеркивания, то код запуска / выполнения (который обычно пишется на ассемблере) может безопасно использовать метки и символы, которые не начинаются с подчеркивания (например, символ "начало"). ").
даже если вы напишите функцию start() в коде c, она будет сгенерирована как _start в выходных данных объекта /asm. (обратите внимание, что в этом случае код c не может сгенерировать символ, который не начинается с подчеркивания), поэтому стартовому кодировщику не нужно беспокоиться о изобретении непонятных невероятных символов (таких как $_dontuse42%$) для каждого из его / ее глобальные переменные / метки.
так что компоновщик не будет жаловаться на конфликт имен, и программист счастлив.:)
следующее отличается от практики компилятора, добавляющего подчеркивание в его выходные форматы.
Впоследствии эта практика была кодифицирована как часть стандартов языка C и C++, в которых использование ведущих подчеркиваний было зарезервировано для реализации.
это соглашение соблюдается для библиотек c sytem и других системных компонентов. (и для таких вещей, как __FILE__ и т. д.).
(обратите внимание, что такой символ (например, _time) может приводить к двум ведущим подчеркиваниям (__time) в сгенерированном выводе)
Из того, что я всегда слышу, это избегание конфликтов имен. Не для других внешних переменных, а для того, чтобы при использовании библиотеки она не конфликтовала с именами переменных пользовательского кода.
Основная функция не является реальной точкой входа исполняемого файла. Некоторые статически связанные файлы имеют реальную точку входа, которая в конечном итоге вызывает main, и эти статически связанные файлы имеют пространство имен, которое не начинается с подчеркивания. В моей системе в / usr / lib есть gcrt1.o, crt1.o и dylib1.o. У каждого из них есть функция "start" без подчеркивания, которая в конечном итоге вызовет точку входа "_main". Все остальное, кроме этих файлов, имеет внешнюю область видимости. История имеет отношение к смешиванию ассемблера и C в проекте, где все C считались внешними.
Из Википедии:
Для компиляторов Си было обычной практикой ставить перед всеми внешними идентификаторами программ области видимости подчеркивание, чтобы предотвратить конфликты с вкладами языковой поддержки во время выполнения. Кроме того, когда компилятору C/C++ необходимо было вводить имена во внешнюю связь как часть процесса перевода, эти имена часто отличались некоторой комбинацией нескольких начальных или конечных подчеркиваний.
Впоследствии эта практика была кодифицирована как часть стандартов языка C и C++, в которых использование ведущих подчеркиваний было зарезервировано для реализации.