Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将C转换为MIPS_C_Mips_Mips32 - Fatal编程技术网

将C转换为MIPS

将C转换为MIPS,c,mips,mips32,C,Mips,Mips32,我在将C转换为MIPS时遇到一些问题。 我目前无法将此C代码转换为MIPS: int arraySum(int* array, int arraySize) { int result; if(arraySize == 0) result = 0; else result = *array + arraySum(&array[1], arraySize-1); return result; } 我在MIPS中创建的当前代码如下:

我在将C转换为MIPS时遇到一些问题。 我目前无法将此C代码转换为MIPS:

int arraySum(int* array, int arraySize)
{
   int result;

   if(arraySize == 0)
      result = 0;
   else
      result = *array + arraySum(&array[1], arraySize-1);

   return result;
}
我在MIPS中创建的当前代码如下:

    arraySum:
         addi $sp, $sp, -4
         sw $ra, 0($sp)
         
         beqz $a1, rec_done
         li $v0, 0
         j rec
    rec:
        addi $a1, $a1, -1
        jal arraySum
        addi $a1, $a1, 1
    rec_done:
        sll $t2, $a1, 2
        add $t2, $a0, $t2
        lw $t2, 0($t2)
        addu $v0, $t2, $v0

        lw $ra, 0($sp)
        addiu $sp, $sp, 4
        jr $ra

很抱歉,它没有注释,我通常在代码完成后键入我的注释

您这样做是作为家庭作业,目的不是消除或优化递归,而是以赋值所期望的递归精神翻译函数,这样您就可以了解堆栈帧、返回地址、,变量存在于调用中,等等

上面注释中为编译器示例提供的链接对代码进行了非常严格的优化,因此您应该学习的课程都不会保留在生成的代码中。(我们都知道递归对数组的连续值求和有点过分,但这就是赋值。)

您的代码需要在
jal
之后执行一些操作,因为在某个时刻(正常工作时),它会在递归
jal
之后返回到指令

每个返回路径上都需要进入
$v0
-返回地址(寄存器$ra;在旧术语中有时称为链接)和返回值(寄存器$v0)之间存在差异。两者都是必要的,但它们是独立的概念,因此,不要使用/混淆两者。返回地址是指向机器代码指令的指针,用于将处理器指令流的控制权返回给调用者;而这里的返回值只是一个整数值,如0或总和,用于将函数answer返回给调用者

递归是一个函数调用另一个函数(原来是同一个函数)。在处理调用函数(模高级优化)时,我们需要保留调用之前定义和调用之后使用的值

首先,返回地址是函数末尾需要的参数值,用于返回调用方(
jr$ra

另一方面,让我们更仔细地看一下这个表达式:

*array + arraySum(&array[1], arraySize-1)
显然,在调用
arraySum
返回一个操作数之前,我们无法添加(
+
)。因此,根据您的编码方式,调用后需要
array
*array
。(递归并不重要:以相同方式调用任何对象都需要类似的分析。)

根据C语言标准,C编译器(实现)可以在调用
arraySum
之前或之后自由地取消引用
array
(如
*array
),函数调用后还需要一个值:如果取消引用是在函数调用之前完成的,则需要保留被取消引用元素的值以供函数调用之后的add使用,或者如果取消引用延迟,则必须保留
数组
参数本身以进行取消引用(以及接下来的添加)电话之后

因此,此函数需要两个项才能在函数调用后生存。一个是返回地址,另一个是
数组
参数或
*数组
元素值


让我们任意选择在函数返回后取消对
数组
参数的引用

保存这些项是使用堆栈空间完成的-通过分配堆栈帧。分配堆栈帧意味着在返回调用方之前在末尾取消分配它。由于此代码是无循环表示的,因此在此处使用
$s
寄存器没有必要也没有好处,因此,函数序言应该只分配2个字的堆栈空间,并将返回地址存储在那里(
$ra
)和
数组
$a0
)。为了在函数调用后进行加法,应该从堆栈中重新加载
数组
参数的值,取消引用,并添加到函数调用的返回值(
$v0

函数尾声应重新加载返回地址(
$ra
)并释放堆栈空间。(无需为调用方还原(
$a0


另一种方法是在函数调用之前解引用
数组
,这意味着将使用一个字的堆栈空间来保存解引用的值,因此可以在函数调用之后重新创建

同样,分配堆栈空间的2个字,并将返回地址存储在其中一个字中。另一个字用于计算上述加法表达式,因此解引用发生在调用之前,其值存储在另一个堆栈分配字中。函数调用之后,该解引用值被还原到寄存器中,这样加法的两个操作数现在都在寄存器中,并且可以求和到
$v0


尾声需要还原返回地址,否则释放堆栈空间,然后返回给调用者。

以下是GCC为您的代码生成的内容:寄存器名称看起来不同,但可能会有所帮助。为什么“手动将C编译为MIPS程序集”这样一个流行的赋值?好问题Shawn,我想亲自了解一下,不过,唉,我真是一窍不通。谢谢Jerry的建议,我会尝试一下。@Shawn也许他们认为这会有助于了解编译器的工作原理。实际上,我使用这些知识来查找编译器错误。是的,有这样的野兽。然而,另一种方式看起来更适合我。只有我的$0.02。我已经在原始帖子中更新了我的代码。请看一看它,看看它是否达到了您的目的。这是在保存和恢复回信地址方面的一项改进,
$ra
。传递给递归调用的参数更糟糕:它需要传递2个参数。不确定它为什么要执行
array[arraysize]
,因为这根本不在C代码中。从技术上讲,我们不应该依赖参数(
$a
)寄存器来保留它们的值