如何重构此 C++ 以删除标签/goto?

问题描述 投票:0回答:4

我的问题并不是真正的问题,但我想让这段代码看起来比现在更优雅一点。它有意大利面条代码。

这是我得到的一个小例子。

 int func(...) {
  if ( ... )
  {
    v6 = ESI_1C;
    EBP = 1;
    v5 = 0;
    v21 = 0;
    v19 = 0;
    v25 = ESI_1C;
    if ( packetSize > 1 )
    {
      v26 = (unsigned __int8)initialCryptAnswer;
      v10 = v8 - v6;
      v11 = v6 + 4;
      for ( i = v8 - v6; ; v10 = i )
      {
        v12 = *(DWORD *)(v10 + v11);
        v21 += v12;
        cryptAnswer = (unsigned __int8)cryptTable[(2 * (unsigned __int8)v26)+1];
        v13 = EBP & 3;
        if ( !(EBP & 3) )
          break;
        if ( v13 == 1 ) {
          v16 = cryptAnswer >> 1;
          *(DWORD *)v11 = v12 - v16;
        } else if ( v13 == 2 ) {
          *(DWORD *)v11 = v12 + 2 * cryptAnswer;
        } else if ( v13 == 3 ) {
          v16 = cryptAnswer >> 2;
          *(DWORD *)v11 = v12 - v16;
        }
LABEL_19:
        v17 = *(DWORD *)v11 + v19;
        ++EBP;
        v11 += 4;
        v19 = v17;
        ++v26;
        if ( EBP >= packetSize )
        {
          ESI = v24;
          v5 = v17;
          v6 = v25;
          goto LABEL_22; //kinda like break it's much more because it's instead of a for loop too.
        }
      }
      *(DWORD *)v11 = v12 + 4 * cryptAnswer;
      goto LABEL_19; //this is a looper
    }
LABEL_22:
    result = 1;
  } else {
    result = 0;
  }
  return result;
}

我该怎么做才能摆脱标签而不弄乱代码流程,因为它是加密函数非常重要的一部分?

c++ c label goto
4个回答
2
投票

第二个答案,因为问题改变了很多。

删除所有多余的东西后,原始代码看起来像:

for (... ; ; ...)
{
  ...
  if (...)
  {
    break;
  }
  ABC
LABEL_19:
  DEF
}
XYZ;
goto LABEL_19;

这与:

完全相同
for (... ; ; ...)
{
  ...
  if (...)
  {
    XYZ;
  }
  else
  {
    ABC
  }

  DEF
}

完成此重写后,您可以将

goto LABEL_22
替换为简单的
break

编辑:或更明确地说:

for (... ; ; ...)
{
  ...
  if (! (ESP & 3) )
  {
    // This line used to be located after the loop.
    *(DWORD *)v11 = v12 + 4*cryptAnswer;  // 111
  }
  else
  {
    if (v13 == 1)
    {
      ...
    }
    else if (v13 == 2)
    {
      ...
    }
    else if (v13 == 3)
    {
      ...
    }
  }

  // This is where LABEL_19 used to be.

  v17 = ...      // 222
}

像这样重写代码时的经验法则是代码应该以与以前相同的顺序执行相同的操作。您根本不能盲目地移动代码,为此您必须了解代码的流程。在这种情况下,当第一个

if
被获取时,我用
// 111
标记的行首先被执行,然后是
// 222
行,没有别的。


1
投票

goto LABEL_1
永远不会被执行,因为无法跳出
for
循环。

删除此选项后,您可以将

goto LABEL_2
替换为
break
,或者更好的是简单地替换
return 1;
(如果
result = 1; return 1;
不是局部变量,则使用
return
。)


1
投票

如果您剪切并粘贴代码会更好,这样我们就可以将其剪切并粘贴到编辑器中,但基本上 goto Label_19 之前的行需要转到断行所在的位置。 Break 后面的 if 语句需要成为 else if,并且 goto 标签 22 可以成为一个break(或者将导致 goto 标签 22 的条件移动到 for 循环中,就像我之前的答案一样)到 for 循环中。

PS:你的秘密对于任何拥有可执行文件的人来说都不是秘密


0
投票

答案是删除 break 语句,并将检查

if/else if
v13==1
v13==2
v13==3
块嵌套在新的 if 语句中检查 true 而不是 false,并在
goto LABEL_19
之前使用 else 语句运行赋值并删除标签和 goto 语句。

if(EBP & 3){
    if (v13==1){
        v16 = cryptAnswer >> 1;
        *(DWORD *)v11 = v12 - v16;
    }
    if (v13==2){
        *(DWORD *)v11 = v12 + 2 * cryptAnswer;
    }
    if (v13==3){
        v16 = cryptAnswer >> 2;
        *(DWORD *)v11 = v12 - v16;
    }
} else {*(DWORD *)v11 = v12 + 4 * cryptAnswer;}

break 语句

ONLY
可以跳过 v13 上的等效性检查,这仅通过决策结构就可以实现。等效性检查不需要
else if
语句,这就是我的解决方案消除它们的原因。我回答这个问题是因为提出问题的人让答案被认为是正确的,而且大部分都是正确的,但第一个例子是不正确的,并且没有给出为什么第二个例子有效的原因。

© www.soinside.com 2019 - 2024. All rights reserved.