Typedefs, (двоичный) дублирование кода и объектный файл

Предположим, я скомпилирую исходный файл, содержащий этот фрагмент кода,

struct Point
{
    int x;
    int y;
};

struct Size
{
    int x;
    int y;
};

Поскольку Point и Size абсолютно одинаковы (с точки зрения расположения памяти их элементов), будет ли компилятор генерировать дублирующийся код (по одному для каждого struct) в объектном файле? Это мой первый вопрос.


Теперь давайте удалим struct Size из исходного кода и вместо этого определим его, используя typedef, вот так:

typedef Point Size;

Что теперь будет делать компилятор? Будет ли дублироваться код (поскольку typedef — это не просто переименование, а нечто большее)?


Теперь предположим, что у нас есть такой шаблон класса:

template <int UnUsed>
class ConcreteError : public BaseError {
public:
    ConcreteError () :BaseError(), error_msg() {}

    ConcreteError (int errorCode, int osErrorCode, const std::string& errorMessage)
        :BaseError(errorCode, osErrorCode, errorMessage){}
};

Затем мы настраиваем несколько определений, например,

typedef ConcreteError<0> FileError;
typedef ConcreteError<1> NetworkError;
typedef ConcreteError<2> DatabaseError;

Поскольку параметр шаблона int UnUsed не используется в реализации класса (просто предположим, что), поэтому кажется, что эта ситуация точно такая же, как несколько классов, имеющих точно такое же расположение памяти (аналогично случаю struct Point и struct Size), будет ли дублировать код в объектном файле?

А что, если мы поступим так,

typedef ConcreteError<0> FileError;
typedef ConcreteError<0> NetworkError;
typedef ConcreteError<0> DatabaseError;

Стала ли эта ситуация лучше, поскольку теперь мы используем тот же инстанцированный класс в определениях типов?

PS: этот код шаблона класса взят отсюда:

Как создать производные классы из базового класса с помощью шаблонного программирования на C++?


На самом деле, я понятия не имею, как компилятор генерирует объектный файл из исходного кода и как он обрабатывает имена классов, их члены, другие символы и все такое. Как он обрабатывает typedefs? Что он делает с этим,

typedef int ArrayInt[100];

Является ли ArrayInt новым типом здесь? Какой код компилятор создает для него в объектном файле? Где хранится 100?


person Nawaz    schedule 17.12.2010    source источник


Ответы (3)


Ни одна строка из ваших примеров не сгенерирует никакого кода в объектном файле. Или, точнее, он вообще не будет генерировать никаких данных. Я думаю, что «код» означает просто инструкции процессора.

Данные в объектном файле делятся на три сегмента: код, статические данные и постоянные данные.

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

Статические данные генерируются путем определения глобальных переменных, статических переменных-членов (опять же, фактических определений, а не только объявлений внутри класса) и статических локальных переменных. Переменная не должна быть объявлена ​​с модификатором const для перехода к статическому сегменту данных.

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

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

Если я действительно что-то не упустил, ничто другое в программе не генерирует никаких данных в объектном файле, особенно объявления и определения типов. Они используются внутри компилятора. Поэтому, когда компилятор видит определение структуры, он запоминает, что оно состоит из двух 32-битных целых чисел. Когда он находит реальный код, использующий эту структуру, он знает, что должен сгенерировать код, который работает с двумя 32-битными целыми числами, должен выделить не менее 8 байтов для его хранения и так далее. Но вся эта информация используется внутри во время компиляции и на самом деле не попадает в объектный файл. Если бы в C++ было что-то вроде отражения, это была бы совсем другая история.

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

person Sergei Tachenov    schedule 17.12.2010

Во-первых, для первых определений структур, которые вы включили, код не генерируется, поэтому сравнивать два типа несколько бессмысленно. Но в C++ имена типов важны, поэтому struct A определенно обрабатывается отдельно от struct B.

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

ConcreteError<0> — это другой тип, чем ConcreteError<1>.

Я не думаю, что что-то мешает компилятору быть напуганным и использовать искаженные имена функций в одном и том же коде, когда параметры идентичны с точки зрения расположения данных, и функциям не нужно вызывать другие подфункции для данных, которые имеют разные фактические значения. типы и функции делают то же самое с обоими типами , но я не думаю, что это действительно делается на практике. На самом деле есть компиляторы, которые что-то делают (см. комментарий Бена ниже).

Для последнего typedef (все являются псевдонимами ConcreteError<0>) создается только одна "версия" ConcreteError (поскольку создается экземпляр только этой версии).

person lijie    schedule 17.12.2010
comment
@lijie: не могли бы вы объяснить, почему для первых определений структуры не генерируется код? - person Nawaz; 17.12.2010
comment
потому что они просто определения типов. по сути, они просто сообщают компилятору, что означают имена типов. вы на самом деле не определяете переменные или функции (которые фактически генерируют код). - person lijie; 17.12.2010
comment
@liljie: я думал, вы предположите, что я использую эти структуры в своем коде. то есть определял некоторые переменные, манипулировал ими и делал всевозможные вещи! - person Nawaz; 17.12.2010
comment
@Nawaz: но вы спросили, генерирует ли компилятор повторяющийся код (по одному для каждой структуры), что подразумевает, что вы спрашиваете, генерируют ли сами определения типов дублирующийся код. но они не генерируют код! если вы используете структуры, единственный раз, когда вы дублируете код, это когда у вас есть 2 функции, которые не должны были бы быть 2 функциями, если бы типы были одинаковыми. - person lijie; 17.12.2010
comment
@lijie: re: ‹quote›Я не думаю, что это действительно делается на практике‹/quote›, вы можете прочитать о параметр компоновщика MSVC /OPT:ICF - person Ben Voigt; 17.12.2010
comment
@бен: я впечатлен. Отредактировано, чтобы отразить. - person lijie; 17.12.2010

Нет, дублировать код с неиспользованными PODS нельзя. Если вы их используете, в памяти будет выделено два целых числа и, возможно, некоторое дополнение. Конечно, все они будут выглядеть одинаково, поэтому то, что вы хотите назвать, является спорным, но это не более «дублирование», чем использование одного и того же типа в двух местах.

Нет, дубликатов кода с псевдонимами нет. На самом деле никакого кода.

Возможно, зависит от того, использует ли компилятор определенные оптимизации.

Может быть. Зависит от того, используются ли ваши определения типов в разных единицах перевода и насколько хорошо ваш компилятор удаляет повторяющиеся экземпляры.

Нет, это псевдоним для int[100].

В значительной степени вопрос о том, «сколько машинного кода получается из этой конструкции», полностью зависит от реализации.

person Edward Strange    schedule 17.12.2010