Вопросы по искажению имен в C++
Я пытаюсь выучить и понять искажение имени в C++. Вот несколько вопросов:
(1) от devx
Когда глобальная функция перегружена, сгенерированное искаженное имя для каждой перегруженной версии является уникальным. Имя искажения также применяется к переменным. Таким образом, локальная переменная и глобальная переменная с тем же именем, заданным пользователем, все еще получают разные искаженные имена.
Существуют ли другие примеры, которые используют искажение имен, кроме перегрузки функций и глобальных и локальных переменных с тем же именем?
(2) из вики
Возникает необходимость, когда язык позволяет именовать разные сущности с одинаковым идентификатором, если они занимают другое пространство имен (где пространство имен обычно определяется модулем, классом или явной директивой пространства имен).
Я не совсем понимаю, почему искажение имен применяется только в тех случаях, когда идентификаторы принадлежат разным пространствам имен, поскольку функции перегрузки могут находиться в одном и том же пространстве имен, а глобальные и локальные переменные с одинаковыми именами также могут находиться в одном и том же пространстве. Это как понять?
Переменные с одинаковыми именами, но в разных областях также используют искажение имен?
(3) Есть ли у C искажение имени? Если это не так, как он может справиться со случаем, когда некоторые глобальные и локальные переменные имеют одинаковые имена? C не имеет функций перегрузки, верно?
Спасибо и всего наилучшего!
5 ответов
C не работает с искажением имен, хотя он предваряет подчеркивание именам функций, поэтому printf(3)
на самом деле _printf
в объекте libc.
В C++ история другая. История этого заключается в том, что первоначально Страуструп создал "C с классами" или cfront, компилятор, который переведет ранний C++ в C. Затем остальные инструменты - компилятор C и компоновщик мы использовали бы для создания объектного кода. Это подразумевало, что имена C++ должны были как-то переводиться в имена C. Это именно то, что делает название Манглинг. Он предоставляет уникальное имя для каждого члена класса, а также функцию и переменную глобального / пространства имен, поэтому имена пространств и классов (для разрешения) и типы аргументов (для перегрузки) так или иначе включены в окончательные имена компоновщиков.
Это очень легко увидеть с помощью таких инструментов, как nm(1)
- скомпилируйте исходный код C++ и посмотрите на сгенерированные символы. Следующее на OSX с GCC:
namespace zoom
{
void boom( const std::string& s )
{
throw std::runtime_error( s );
}
}
~$ nm a.out | grep boom
0000000100001873 T __ZN4zoom4boomERKSs
И в C, и в C++ локальные (автоматические) переменные не производят никаких символов, но живут в регистрах или в стеке.
Редактировать:
Локальные переменные не имеют имен в результирующем объектном файле по простой причине, что компоновщик не должен знать о них. Так что ни имени, ни увечья. Все остальное (на что должен смотреть этот компоновщик) искажено в C++.
Mangling - это просто то, как компилятор делает компоновщик счастливым.
В C не может быть двух функций с одинаковым именем, несмотря ни на что. Так вот, что предполагал компоновщик: уникальные имена. (Вы можете иметь статические функции в разных блоках компиляции, потому что их имена не представляют интереса для компоновщика.)
В C++ вы можете иметь две функции с одинаковыми именами, если они имеют разные типы параметров. Таким образом, C++ каким-то образом объединяет имя функции с типами. Таким образом, компоновщик видит их как имеющие разные имена.
Обратите внимание, что не имеет значения, как искажается имя, и фактически каждый компилятор делает это по-своему. Все, что имеет значение, - то, что каждая функция с тем же самым базовым именем так или иначе сделана уникальной для компоновщика.
Теперь вы можете видеть, что добавление в смесь пространств имен и шаблонов продолжает расширять этот принцип.
Технически это "украшение". Это звучит менее грубо, но также покалывание подразумевает, что CreditInterest
может быть переставлен в IntCrederestit
в то время как то, что на самом деле происходит, больше похоже на _CreditInterest@4
который, честно говоря, "украшен" более, чем изуродован. Тем не менее, я тоже называю это искажением:-), но вы найдете больше технической информации и примеров, если будете искать "C++ name художественное оформление".
Существуют ли другие примеры, которые используют искажение имен, кроме перегрузки функций и глобальных и локальных переменных с тем же именем?
C++ наносит вред всем символам, всегда. Это просто проще для компилятора. Обычно искажение кодирует что-то в списке параметров или типах, так как это наиболее распространенные причины необходимости искажения.
С не калечит. Область видимости используется для контроля доступа к локальным и глобальным переменным с одинаковым именем.
Источник: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
Упорядочивание имен - это процесс, используемый компиляторами C++, которые дают каждой функции в вашей программе уникальное имя. В C++, как правило, программы имеют как минимум несколько функций с одинаковыми именами. Таким образом, искажение имени может рассматриваться как важный аспект в C++.
Пример: Обычно имена членов генерируются уникальным образом путем объединения имени члена с именем класса, например, с учетом объявления:
class Class1
{
public:
int val;
...
};
val становится примерно таким:
// a possible member name mangling
val__11Class1
У agner больше информации о том, что такое искажение имени и как это делается в разных компиляторах.
Упорядочивание имен (также называемое оформлением имен) - это метод, используемый компиляторами C++ для добавления дополнительной информации к именам функций и объектов в объектных файлах. Эта информация используется компоновщиками, когда на функцию или объект, определенный в одном модуле, ссылаются из другого модуля. Имя искажения служит следующим целям:
- Сделайте так, чтобы компоновщики могли различать разные версии перегруженных функций.
- Сделайте так, чтобы компоновщики могли проверять, что объекты и функции объявляются одинаково во всех модулях.
- Сделайте так, чтобы компоновщики могли предоставлять полную информацию о типе неразрешенных ссылок в сообщениях об ошибках.
Перенос имени был изобретен для достижения цели 1. Другие цели - это дополнительные преимущества, которые не полностью поддерживаются всеми компиляторами. Минимальная информация, которая должна быть предоставлена для функции, - это имя функции и типы всех ее параметров, а также любые классификаторы классов или пространств имен. Возможная дополнительная информация включает в себя тип возврата, соглашение о вызовах и т. Д. Вся эта информация кодируется в единую текстовую строку ASCII, которая выглядит загадочно для человека-наблюдателя. Компоновщик не должен знать, что означает этот код для выполнения целей 1 и 2. Он должен только проверять идентичность строк.