2010-10-02 2 views
0

В любой среде программирования, какой бы тип данных я не собирался выбрать, CPU будет выполнять только операции Арифметики (операции добавления/логического).Пользовательский тип данных/операции с набором команд процессора

Как этот переход (от определяемый пользователем тип данных/операций набора команд CPU) происходит и какова роль компилятора, интерпретатора, ассемблер и компоновщик в этом жизненном цикле

Кроме того, как OOPS обрабатывает это отображение, так как В худшем случае все объекты являются объектами в OOPS (я имею в виду язык Java).

+0

"OOPS"? o rly? OOP = объектно-ориентированное программирование, s неверно, так как вряд ли существует множественное число, и даже если это было, это не часть аббревиатуры. Я предпочитаю термин «язык (ы) OO» для того, что вы, возможно, означаете. – delnan

+2

@ delnan: две возможности: OOPS = объектно-ориентированная система программирования. Или он действительно знал больше о Java, чем вы понимаете, и имел в виду назвать это «oops», но заглавными, чтобы подчеркнуть, что это * огромная ошибка, а не только небольшая. :-) –

ответ

3

Источник Java -> нативный код перевода фактически происходит в двух разных шагах: преобразование из исходного кода в байт-код во время компиляции (вот что javac) и преобразование из байт-кода в собственные инструкции процессора во время выполнения (это то, что делает java).

Когда исходный код «компилируется», поля и методы сжимаются в записи в таблице символов. Вы говорите «System.out.println()», а javac превращает его во что-то вроде «получить статическое поле, на которое ссылается символ # 2004, и вызывать метод, обозначенный символом № 300 на нем» (где # 2004 может быть « System.out "и # 300 может быть" void java.io.PrintStream.println() "). (Заметьте, я просто упрощаю - символы выглядят не так, и они немного больше разбиты, но они содержат такую ​​информацию.)

Во время выполнения JVM просматривает эти символы , загружает классы, упомянутые в них, и запускает (или генерирует, если это JITting) собственные инструкции, необходимые для поиска и выполнения метода. В Java нет реального «компоновщика»; все ссылки выполняются во время выполнения, на основе ссылочных классов. Это очень похоже на то, как DLL работают в Windows.

JIT - это самая близкая вещь для «ассемблера». Он принимает байт-код и генерирует эквивалентный собственный код на лету. Однако байт-код не в удобочитаемой форме, поэтому я обычно не считаю перевод «сборкой».

...

В таких языках, как C и C++ (не C++/CLI), история совершенно иная. Весь перевод (и хорошая привязка) происходит во время компиляции. Доступ к членам struct преобразуется во что-то вроде «дайте мне int 4 байта с начала этой конкретной группы байтов». Там нет никакой гибкости; если структура структуры изменяется, как правило, все приложение необходимо перекомпилировать.

1

Рассмотрим начальную точку языка, который имеет только целые числа и поплавки различных размеров, и тип, указывающий на память, который позволяет нам указывать на эти типы.

Корреляция от этого к машинным кодам, используемым ЦП, будет относительно ясной (хотя на самом деле мы могли бы оптимизировать за пределами этого).

Символы, которые мы можем добавить, сохраняя коды в некоторой кодировке, и строки, которые мы создаем как массивы таких символов.

Теперь давайте говорить, что мы хотим, чтобы переместить это в точку, где мы можем иметь что-то вроде:

class User 
{ 
    int _id; 
    char* _username; 
    public User(int id, char* username) 
    { 
    _id = id; 
    _username = username; 
    } 
    public virtaul bool IsDefaultUser() 
    { 
    return _id == 0; 
    } 
} 

Первое, что нам нужно добавить к нашему языку какая-то структура/класса конструкции, которая содержит члены.Тогда мы можем иметь, насколько:

class User 
{ 
    int _id; 
    char* _username; 
} 

Наш процесс компиляции знает, что это означает хранение целое, за которым следует указатель на массив символов. Поэтому он знает, что доступ к _id означает доступ к целому числу по адресу начала структуры, а доступ к _username означает доступ к указателю на char при заданном смещении от адреса начала структуры.

Учитывая это, конструктор может существовать как функция, которая делает что-то вроде:

_ctor_User*(int id, char* username) 
    { 
    User* toMake = ObtainMemoryForUser(); 
    toMake._id = id; 
    toMake._username = ObtainMemoryAndCopyString(username); 
    return toMake; 
    } 

Получение памяти и очистки его при необходимости является сложным, посмотрите на раздел в K & R о том, как использовать указатели на структуры и как malloc ищет один способ, которым это можно было бы сделать.

С этого момента мы можем реализовать IsDefaultUser что-то вроде:

bool _impl_IsDefaultUser(*User this) 
{ 
    return this._id == 0 
} 

Это не может быть переопределен, хотя. Для того, чтобы позволить переопределение мы изменяем Пользователь быть:

class User 
{ 
    UserVTable* _vTable; 
    int _id; 
    char* _username; 
} 

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

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

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

Смежные вопросы