用户定义的数据类型/操作到CPU指令集

时间:2010-10-02 12:54:34

标签: c oop compiler-construction programming-languages

在任何编程环境中,我将选择的数据类型最终CPU将仅执行算术运算(加法/逻辑运算)。

如何发生这种转换(从用户定义的数据类型/操作到CPU指令集)以及编译器,解释器,汇编器和链接器在此生命周期中的作用

OOPS如何处理这种映射,因为最坏的情况大多数都是OOPS中的对象(我的意思是Java语言)..

2 个答案:

答案 0 :(得分:3)

Java源代码 - >本机代码转换实际上发生在两个不同的步骤中:在编译时从源代码转换为字节码(这是javac所做的),以及在运行时从字节码到本机CPU指令的转换(这就是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成员的访问转换为“从这一特定字节的开头给我4个字节的int”。那里没有灵活性;如果结构的布局发生变化,通常必须重新编译整个应用程序。

答案 1 :(得分:1)

考虑一个只有整数和不同大小的浮点数的语言的起点,以及一个指向内存的类型,它允许我们指向这些类型。

从此到CPU使用的机器代码的相关性将相对清晰(尽管实际上我们可能会优化超出此范围)。

我们可以通过在某些编码中存储代码点来添加的字符,以及我们构建为此类字符数组的字符串。

现在让我们说我们想把它移到我们可以拥有的东西:

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
}

但这不能被覆盖。为了允许覆盖,我们将User更改为:

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

然后_vTable指向一个指向函数的指针表,在这种情况下,它包含一个单独的条目,这是一个指向上述函数的指针。然后调用虚拟成员变成了查看该表中的正确偏移量并调用找到的相应函数的问题。派生类将具有不同的_vTable,除非为那些被覆盖的方法设置不同的函数指针,否则它们将是相同的。

这是一个很大的问题,而不是每种情况下唯一的可能性(例如,v-table不是实现可覆盖方法的唯一方法),但确实显示了我们如何构建面向对象的语言,这可能是在更原始的数据类型上编译为更原始的操作。

它还掩盖了做C#编译成IL的方式的可能性,然后又编译成机器代码,因此OO语言和机器代码之间有两个步骤实际上会被执行。