вопросы по искажению имен в C ++ - PullRequest
23 голосов
/ 30 мая 2010

Я пытаюсь выучить и понять искажение имени в C ++. Вот несколько вопросов:

(1) От devx

Когда глобальная функция перегружена, сгенерированное искаженное имя для каждой перегруженной версии является уникальным. Имя искажения также применяется к переменным. Таким образом, локальная переменная и глобальная переменная с тем же именем, заданным пользователем, все еще получают разные искаженные имена.

Существуют ли другие примеры, в которых используется искажение имен, помимо перегрузки функций и одноименных глобальных и локальных переменных?

(2) Из Wiki

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

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

Используют ли переменные с одинаковыми именами, но в разных областях также искажение имен?

(3) У C есть искажение имени? Если это не так, как он может справиться со случаем, когда некоторые глобальные и локальные переменные имеют одинаковые имена? C не имеет функций перегрузки, верно?

Спасибо и всего наилучшего!

Ответы [ 6 ]

26 голосов
/ 30 мая 2010

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 ++ локальные (автоматические) переменные не производят никаких символов, но живут в регистрах или в стеке.

Edit:

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

16 голосов
/ 30 мая 2010

Mangling - это просто то, как компилятор поддерживает компоновщик.

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

В C ++ вы можете иметь две функции с одинаковыми именами, если они имеют разные типы параметров. Таким образом, C ++ каким-то образом объединяет имя функции с типами. Таким образом, компоновщик видит их как имеющие разные имена.

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

Теперь вы можете видеть, что добавление пространств имен и шаблонов к миксу продолжает расширять принцип.

9 голосов
/ 30 мая 2010

Технически, это "украшение". Это звучит менее грубо, но также и искажение означает, что CreditInterest может быть преобразовано в IntCrederestit, тогда как то, что на самом деле происходит, больше похоже на _CreditInterest@4, который, честно говоря, «украшен» больше, чем искалечен. Тем не менее, я тоже называю это искажением :-), но вы найдете больше технической информации и примеров, если будете искать "C ++ name художественное оформление".

5 голосов
/ 30 мая 2010

Существуют ли другие примеры, в которых используется искажение имен, кроме функций перегрузки и глобальных и локальных переменных с тем же именем?

C ++ mangles все символы, всегда. Это просто проще для компилятора. Как правило, искажение кодирует что-то в списке параметров или типах, так как это наиболее распространенные причины необходимости искажения.

С не калечит. Область видимости используется для контроля доступа к локальным и глобальным переменным с одинаковым именем.

2 голосов
/ 21 марта 2014

Источник: 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
0 голосов
/ 25 апреля 2019

agner содержит больше информации о том, что такое искажение имени и как это делается в разных компиляторах.

искажение имени (также называемое оформлением имени) - это метод, используемый в C ++ компиляторы для добавления дополнительной информации к именам функций и объекты в объектных файлах. Эта информация используется компоновщиками, когда на функцию или объект, определенный в одном модуле, ссылаются из другого модуль. Имя искажения служит для следующих целей:

  1. Позволяют компоновщикам различать разные версии перегруженных функций.
  2. Предоставить компоновщикам возможность проверять, что объекты и функции объявляются одинаково во всех модулях.
  3. Предоставить компоновщикам возможность предоставлять полную информацию о типе неразрешенных ссылок в сообщениях об ошибках.

Имя искажения было изобретено для выполнения цели 1. Другие цели вторичные преимущества не полностью поддерживаются всеми компиляторами. минимальная информация, которая должна быть предоставлена ​​для функции - это имя функции и типы всех ее параметров, а также любой классификаторы класса или пространства имен. Возможна дополнительная информация включает тип возврата, соглашение о вызовах и т. д. Все это информация кодируется в единую текстовую строку ASCII, которая выглядит загадочно для человеческого наблюдателя. Линкер не должен знать, что этот код означает, что для выполнения целей 1 и 2. он должен только проверьте, идентичны ли строки.

...