C++ 在交换机中嵌套goto循环
我想在一个序列上循环,但我想动态地选择在序列中开始循环的位置。我设计了这种流动模式C++ 在交换机中嵌套goto循环,c++,c,C++,C,我想在一个序列上循环,但我想动态地选择在序列中开始循环的位置。我设计了这种流动模式 switch(offset){ start: currentObject = objects[index++]; //a different object is chosen to be manipulated by the sequence of code case 0: sub_sequence(currentObject); // a sequence that is
switch(offset){
start:
currentObject = objects[index++]; //a different object is chosen to be manipulated by the sequence of code
case 0:
sub_sequence(currentObject); // a sequence that is repeated within the larger sequence of the entire switch
if(enough_actions) break;
case 1:
sub_sequence(currentObject);
if(enough_actions) break;
case 2:
sub_sequence(currentObject);
if(enough_actions) break;
goto start;
}
它似乎很适合我的需要,但我以前从未见过这种设计。这个设计有什么问题吗?我应该选择另一种方式吗?您也可以:
switch(offset)
{
do
{
currentObject = objects[index++]; //a different object is chosen to be manipulated by the sequence of code
case 0:
sub_sequence(); // a sequence that is repeated within the larger sequence of the entire switch
if(enough_actions) break;
case 1:
sub_sequence();
if(enough_actions) break;
case 2:
sub_sequence();
if(enough_actions) break;
}
while (1);
}
所以你避开了goto;)
(如评论中所述,如果需要这种行为,从技术上讲,避免goto
是没有意义的)
但是,你是对的,两者都应该适合你的需要。你也可以这样做:
switch(offset)
{
do
{
currentObject = objects[index++]; //a different object is chosen to be manipulated by the sequence of code
case 0:
sub_sequence(); // a sequence that is repeated within the larger sequence of the entire switch
if(enough_actions) break;
case 1:
sub_sequence();
if(enough_actions) break;
case 2:
sub_sequence();
if(enough_actions) break;
}
while (1);
}
所以你避开了goto;)
(如评论中所述,如果需要这种行为,从技术上讲,避免goto
是没有意义的)
但是,你是对的,两者都应该符合你的需要。你在那里构建的是一个达夫装置。虽然它避免了重复的源代码,但它不仅很难为人类理解,而且也很难为编译器进行优化
switch(offset)
{
case 0:
sub_sequence(currentObject); // a sequence that is repeated within the larger sequence of the entire switch
if(enough_actions) break;
case 1:
sub_sequence(currentObject);
if(enough_actions) break;
case 2:
sub_sequence(currentObject);
if(enough_actions) break;
//a different object is chosen to be manipulated by the sequence of code
currentObject = objects[index++];
while(true) {
sub_sequence(currentObject);
if(enough_actions) break;
sub_sequence(currentObject);
if(enough_actions) break;
sub_sequence(currentObject);
if(enough_actions) break;
currentObject = objects[index++];
}
}
通过将循环与变量入口点分离,编译器可以更自由地执行优化
在原始代码中,它由开始:
标签和3个大小写:
标签分开,这迫使编译器分别处理两个标签之间的每个代码段
如果没有这些标签,编译器现在可以将特定于switch语句的优化应用于switch
块,还可能对while
循环应用额外的循环展开或其他策略
最后,使用可读性更强的变体可能会产生更紧凑和更快的机器代码
这可以说是少数几个可以接受“复制”代码的情况之一,因为开关
和while
块看起来很相似,但行为仍然完全不同
EDIT1:将循环移动到switch语句的末尾,以便正确处理足够多的动作。如果不存在提前退出的条件,则循环可能被置于开关
块之外
奖励:无交换机实施:
for(;!enough_actions;offset = 0,currentObject = objects[index++]) {
for(int i = offset; i < 3 && !enough_actions; i++) {
sub_sequence(currentObject);
}
}
(;!足够多的动作;偏移量=0,当前对象=objects[index++])的{
对于(int i=offset;i<3&!足够多的动作;i++){
子序列(currentObject);
}
}
您在那里构建的是一个达夫装置。虽然它避免了重复的源代码,但它不仅很难为人类理解,而且也很难为编译器进行优化
switch(offset)
{
case 0:
sub_sequence(currentObject); // a sequence that is repeated within the larger sequence of the entire switch
if(enough_actions) break;
case 1:
sub_sequence(currentObject);
if(enough_actions) break;
case 2:
sub_sequence(currentObject);
if(enough_actions) break;
//a different object is chosen to be manipulated by the sequence of code
currentObject = objects[index++];
while(true) {
sub_sequence(currentObject);
if(enough_actions) break;
sub_sequence(currentObject);
if(enough_actions) break;
sub_sequence(currentObject);
if(enough_actions) break;
currentObject = objects[index++];
}
}
通过将循环与变量入口点分离,编译器可以更自由地执行优化
在原始代码中,它由开始:
标签和3个大小写:
标签分开,这迫使编译器分别处理两个标签之间的每个代码段
如果没有这些标签,编译器现在可以将特定于switch语句的优化应用于switch
块,还可能对while
循环应用额外的循环展开或其他策略
最后,使用可读性更强的变体可能会产生更紧凑和更快的机器代码
这可以说是少数几个可以接受“复制”代码的情况之一,因为开关
和while
块看起来很相似,但行为仍然完全不同
EDIT1:将循环移动到switch语句的末尾,以便正确处理足够多的动作。如果不存在提前退出的条件,则循环可能被置于开关
块之外
奖励:无交换机实施:
for(;!enough_actions;offset = 0,currentObject = objects[index++]) {
for(int i = offset; i < 3 && !enough_actions; i++) {
sub_sequence(currentObject);
}
}
(;!足够多的动作;偏移量=0,当前对象=objects[index++])的{
对于(int i=offset;i<3&!足够多的动作;i++){
子序列(currentObject);
}
}
我已经检查了Microsoft编译器为以下斐波那契函数生成的汇编代码,编译器仍然能够稍微修改未展开的循环序列(我假设可以优化寄存器依赖项)
也许这更适用于线性反馈移位寄存器等情况,其中循环被展开以保存变量之间的移位数据。例如:
while(...){
e = f(a,b,c,d);
a = b;
b = c;
c = d;
d = e;
}
展开成
do{
a = f(a,b,c,d);
case 3:
b = f(b,c,d,a);
case 2:
c = f(c,d,a,b);
case 1:
d = f(d,a,b,c);
case 0:
}while(...);
如果元素的数量不是4的倍数,那么使用达夫的设备进入展开的循环 我已经检查了Microsoft编译器为下面的斐波那契函数生成的汇编代码,编译器仍然能够稍微修改展开的循环序列(我假设可以优化寄存器依赖项)
也许这更适用于线性反馈移位寄存器等情况,其中循环被展开以保存变量之间的移位数据。例如:
while(...){
e = f(a,b,c,d);
a = b;
b = c;
c = d;
d = e;
}
展开成
do{
a = f(a,b,c,d);
case 3:
b = f(b,c,d,a);
case 2:
c = f(c,d,a,b);
case 1:
d = f(d,a,b,c);
case 0:
}while(...);
如果元素的数量不是4的倍数,那么使用达夫的设备进入展开的循环 为什么不绕着开关转一圈呢?您可以避免跳转。您只需将其插入while
循环中即可。@RichardHodges如果您在linux内核中看到Duff的设备,请立即提交修补程序。将循环从switch语句中切掉,从而“展开”Duff的设备,可以提高可读性,并使编译器能够执行适当的优化,否则这些优化会被这些讨厌的标签阻止。(无论是显式的start:
标签还是switch
语句中的case
标签。)@Ragdoll每当遇到标签时,编译器都必须将代码分成不同的部分。它不再能够在这些部分之间交换或合并指令,或者应用任何其他会改变后一部分行为的优化。在这种情况下,常规循环优化和