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

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

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

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

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

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

5 ответов


это была обычная практика для компиляторов C, чтобы добавить ведущее подчеркивание для всех внешних идентификаторов программ области, чтобы предотвратить столкновения с вкладами от поддержки языка выполнения

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

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

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


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

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

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

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

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

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

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


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


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


с Википедия:

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

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