我正在编译一个简单的C程序,实现一个中序树遍历函数:
void inorderTraversal(struct TreeNode* root) {
if (root == NULL) {
return;
}
inorderTraversal(root->left);
printf("%d ", root->val);
inorderTraversal(root->right);
}
然后我使用以下命令编译 .c 文件:
gcc inorder.c -O2 -o inorder_O2
当我尝试使用 BinaryNinja 反编译 inorder_O2 文件时,我得到了该函数的高级 IL 版本:
void inorderTraversal(int32_t* arg1){
int32_t* i_1 = arg1
if (arg1 != 0)
int32_t* i
do
int32_t* j_2 = *(i_1 + 8)
int32_t* j_1 = j_2
if (j_2 != 0)
int32_t* j
do
int32_t* k_2 = *(j_1 + 8)
int32_t* k_1 = k_2
if (k_2 != 0)
int32_t* k
do
int32_t* r15_1 = *(k_1 + 8)
if (r15_1 != 0)
do
int32_t* rbx_1 = *(r15_1 + 8)
if (rbx_1 != 0)
do
int32_t* r13_1 = *(rbx_1 + 8)
if (r13_1 != 0)
do
int32_t* r12_1 = *(r13_1 + 8)
if (r12_1 != 0)
do
int32_t* r14_1 = *(r12_1 + 8)
if (r14_1 != 0)
do
int32_t* r9_1 = *(r14_1 + 8)
if (r9_1 != 0)
do
inorderTraversal(*(r9_1 + 8))
__printf_chk(flag: 1, format: &data_2004, zx.q(*r9_1))
r9_1 = *(r9_1 + 0x10)
while (r9_1 != 0)
__printf_chk(flag: 1, format: &data_2004, zx.q(*r14_1))
r14_1 = *(r14_1 + 0x10)
while (r14_1 != 0)
__printf_chk(flag: 1, format: &data_2004, zx.q(*r12_1))
r12_1 = *(r12_1 + 0x10)
while (r12_1 != 0)
__printf_chk(flag: 1, format: &data_2004, zx.q(*r13_1))
r13_1 = *(r13_1 + 0x10)
while (r13_1 != 0)
__printf_chk(flag: 1, format: &data_2004, zx.q(*rbx_1))
rbx_1 = *(rbx_1 + 0x10)
while (rbx_1 != 0)
__printf_chk(flag: 1, format: &data_2004, zx.q(*r15_1))
r15_1 = *(r15_1 + 0x10)
while (r15_1 != 0)
__printf_chk(flag: 1, format: &data_2004, zx.q(*k_1))
k = *(k_1 + 0x10)
k_1 = k
while (k != 0)
__printf_chk(flag: 1, format: &data_2004, zx.q(*j_1))
j = *(j_1 + 0x10)
j_1 = j
while (j != 0)
__printf_chk(flag: 1, format: &data_2004, zx.q(*i_1))
i = *(i_1 + 0x10)
i_1 = i
while (i != 0)
}
我猜想进行尾递归消除,因为只剩下一个递归调用。我不知道是什么让这个函数成为一大堆嵌套循环?有确切的编译器优化名称吗?
也就是说,我主要想知道该技术的名称或描述,而不是打开或关闭它的编译器选项。
root->right
上的递归是尾调用,因此可以消除。所有 do-while
循环都是这些被消除的尾部调用。
root->left
上的递归不在尾部位置,所以不能这样消除。相反,编译器使用嵌套的 if
语句对前 8 级递归进行开放代码。
如果树的深度超过 8 层,它会实际回调该函数。您可以在最里面的
do
块中看到这一点。
现在我再多思考一下,我可能会向后思考哪些优化是尾部调用,哪些是非尾部调用。