我正在从C语言过渡到Rust,并且正在寻找一种惯用的方法来重写一个C代码模式,该模式涉及Rust中的switch case和后藤。下面是我的C代码示例:
C代码是从bzip2中提取的 *.i代码
#include <stdio.h>
int main() {
int state = 15;
int dummy = 0;
switch (state) {
case 15:
dummy = 15; // set dummy to 15 under certain condition
if (dummy == 15) goto endhdr_2;
/* fallthrough */
case 16:
dummy = 16;
printf("dummy");
/* fallthrough */
endhdr_2:
case 42:
dummy = 42;
printf("dummy: %d", 42);
/* fallthrough */
case 43:
dummy = 43;
printf("dummy: %d", 43);
/* fallthrough */
default:
break;
}
return 0;
}
字符串
我知道Rust中没有goto
,而Rust的match与C的switch有些不同。我如何才能最好地将这种模式转换到Rust中,同时遵循Rust的惯用做法并确保相同的功能?
为上述代码添加额外的Context
上面我的C代码的例子,它是从classic C program bzip2的代码库中提取的,goto
逻辑具体来自decompress. c中的BZ2_decompress
函数。
我在这里附加了.i
预处理的可读性,它来自.i
文件。
在decompress.i
中使用后藤的位置
case 14: s->state = 14; while (((Bool)1)) { if (s->bsLive >= 8) { UInt32 v; v = (s->bsBuff >> (s->bsLive-8)) & ((1 << 8)-1); s->bsLive -= 8; uc = v; break; } if (s->strm->avail_in == 0) { retVal = 0; goto save_state_and_return; };; s->bsBuff = (s->bsBuff << 8) | ((UInt32) (*((UChar*)(s->strm->next_in)))); s->bsLive += 8; s->strm->next_in++; s->strm->avail_in--; s->strm->total_in_lo32++; if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; };
if (uc == 0x17) goto endhdr_2;
型decompress.i
中endhdr_2:
之后的代码
endhdr_2:
case 42: s->state = 42; while (((Bool)1)) { if (s->bsLive >= 8) { UInt32 v; v = (s->bsBuff >> (s->bsLive-8)) & ((1 << 8)-1); s->bsLive -= 8; uc = v; break; } if (s->strm->avail_in == 0) { retVal = 0; goto save_state_and_return; };; s->bsBuff = (s->bsBuff << 8) | ((UInt32) (*((UChar*)(s->strm->next_in)))); s->bsLive += 8; s->strm->next_in++; s->strm->avail_in--; s->strm->total_in_lo32++; if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; };
if (uc != 0x72) { retVal = (-4); goto save_state_and_return; };;
case 43: s->state = 43; while (((Bool)1)) { if (s->bsLive >= 8) { UInt32 v; v = (s->bsBuff >> (s->bsLive-8)) & ((1 << 8)-1); s->bsLive -= 8; uc = v; break; } if (s->strm->avail_in == 0) { retVal = 0; goto save_state_and_return; };; s->bsBuff = (s->bsBuff << 8) | ((UInt32) (*((UChar*)(s->strm->next_in)))); s->bsLive += 8; s->strm->next_in++; s->strm->avail_in--; s->strm->total_in_lo32++; if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; };
if (uc != 0x45) { retVal = (-4); goto save_state_and_return; };;
case 44: s->state = 44; while (((Bool)1)) { if (s->bsLive >= 8) { UInt32 v; v = (s->bsBuff >> (s->bsLive-8)) & ((1 << 8)-1); s->bsLive -= 8; uc = v; break; } if (s->strm->avail_in == 0) { retVal = 0; goto save_state_and_return; };; s->bsBuff = (s->bsBuff << 8) | ((UInt32) (*((UChar*)(s->strm->next_in)))); s->bsLive += 8; s->strm->next_in++; s->strm->avail_in--; s->strm->total_in_lo32++; if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; };
if (uc != 0x38) { retVal = (-4); goto save_state_and_return; };;
case 45: s->state = 45; while (((Bool)1)) { if (s->bsLive >= 8) { UInt32 v; v = (s->bsBuff >> (s->bsLive-8)) & ((1 << 8)-1); s->bsLive -= 8; uc = v; break; } if (s->strm->avail_in == 0) { retVal = 0; goto save_state_and_return; };; s->bsBuff = (s->bsBuff << 8) | ((UInt32) (*((UChar*)(s->strm->next_in)))); s->bsLive += 8; s->strm->next_in++; s->strm->avail_in--; s->strm->total_in_lo32++; if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; };
if (uc != 0x50) { retVal = (-4); goto save_state_and_return; };;
case 46: s->state = 46; while (((Bool)1)) { if (s->bsLive >= 8) { UInt32 v; v = (s->bsBuff >> (s->bsLive-8)) & ((1 << 8)-1); s->bsLive -= 8; uc = v; break; } if (s->strm->avail_in == 0) { retVal = 0; goto save_state_and_return; };; s->bsBuff = (s->bsBuff << 8) | ((UInt32) (*((UChar*)(s->strm->next_in)))); s->bsLive += 8; s->strm->next_in++; s->strm->avail_in--; s->strm->total_in_lo32++; if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; };
if (uc != 0x90) { retVal = (-4); goto save_state_and_return; };;
型
您可以通过修改CMakeLists.txt来添加add_definitions(-save-temps)
来重现decompress.i
您可以使用以下命令清理 *.i
for file in *.i; do awk '!/^#[ \t]*[0-9]+[ \t]+"/' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"; done
型
1条答案
按热度按时间brqmpdu11#
为了消除每一个
goto
和从一种情况到下一种情况的每一次下降,我们可以重新构造代码,字符串
成为
型
从我刚刚读到的关于Rust的内容来看,这应该很容易翻译。
接下来是我们如何做到这一点。
消除
goto endhdr_2
由于在
goto
之后要做的第一件事是更改switch变量,因此我们可以重新构造代码,型
成为
型
消除跌倒
据我所知,Rust不支持从一种情况下降到下一种情况,而C代码确实做了很多。这种用于消除
goto
的方法可以用来模拟下降到另一种状态。型
成为
型
消除
goto save_state_and_return
第二个
goto
有“百万”个示例:goto save_state_and_return
。goto
的目的是退出开关。goto
代替break
用于跳过开关之后的Assert。因此,只要我们还设置一些变量来指示应该跳过Assert,就可以将goto
替换为break
。我们可以采用我们总是在每个goto save_state_and_return
之前设置retVal
,以避免设置新变量“百万”次。换句话说,我们可以重新构造代码,型
成为
型