在C语言中实现收益率

在C语言中实现收益率,c,yield,C,Yield,例如: int getNext(int n) { while (TRUE) { n = n+1; yield n; } } int main() { while (TRUE) { int n = getNext(1); if (n > 42) break; printf("%d\n",n); } } 这样,上述代码将打印从1到42的所有数字。 我想让yi

例如:

int getNext(int n) {
    while (TRUE) {
        n = n+1;
        yield n;
    }
}

int main() {
    while (TRUE) {
        int n = getNext(1);
        if (n > 42)
           break;
        printf("%d\n",n);
    }
}
这样,上述代码将打印从1到42的所有数字。 我想让
yield
yield
之后更改getNext的地址。但是我不知道如何保存上下文(寄存器/变量),因为堆栈将被调用函数运行

注:


我意识到上面的代码可以很容易地通过静态变量实现,但这不是重点。

您要寻找的是所谓的“协同程序”,并且(至少在不失去一般性的情况下,请参阅另一个答案,了解在有限情况下执行此操作的方法)在便携式C中是不可能的。有许多技巧可以用来伪造它们;请参阅以获取一些信息。

即使在便携式C中也可以这样做。下面是一个简单的示例(
gcc-Wall gen.C
):

#包括
#包括
#包括
#如果(!setjmp(func###u gen_jmp)){\
func###u ret=n\
longjmp(func######u调用者(jmp,1))\
}
#定义生成器(ret、func、argt、argv)\
静态jmp_buf func###u调用者_jmp\
静态jmp_buf func##u gen_jmp\
静态布尔函数###u continue=false\
静态ret func####u ret\
\
无效函数(argt argv)\
\
ret func(argt argv){\
如果(!func###u continue){\
func###u continue=true\
如果(!setjmp(func###u caller _jmp)){\
func###(argv);\
}否则{\
返回函数返回\
}                                         \
}                                           \
否则{\
longjmp(func###u gen#u jmp,1)\
}                                           \
返回0\
}                                             \
void func###(argt argv)
生成器(int,getNext,int,n){
静态整数计数器;
计数器=n;
while(true){
计数器=计数器+1;
收益率(getNext,计数器);
}
}
int main(){
while(true){
int n=getNext(1);
如果(n>42)
打破
printf(“%d\n”,n);
}
返回0;
}

不管你怎么做,你都无法用C#(或其他什么)的语法轻松地完成它。这就是上下文变量和函数指针的用途。@Joe这纯粹是学术性的,只是想知道一般的想法是什么。看看
也许吧。一般来说,
yield
风格的迭代器需要对代码进行一些重构,才能将其转换为状态机(除非你想对堆栈耍些愚蠢的把戏)。你是否只对简单的案例感兴趣,比如在问题中的一个问题,这不是一个问题?或者如果你想用C++写(或者只是看源代码来学习一些技巧),也许已经有了一些有用的东西。
#include <stdbool.h>
#include <stdio.h>
#include <setjmp.h>

#define YIELD(func, n) if (! setjmp(func##_gen_jmp)) {  \
      func##_ret = n;                                   \
         longjmp(func##_caller_jmp, 1);                 \
  }


#define GENERATOR(ret, func, argt, argv)        \
  static jmp_buf func##_caller_jmp;             \
  static jmp_buf func##_gen_jmp;                \
  static bool func##_continue=false;            \
  static ret func##_ret;                        \
                                                \
  void func##__real(argt argv);                 \
                                                \
  ret func(argt argv) {                         \
    if (!func##_continue) {                     \
    func##_continue=true ;                      \
      if (! setjmp(func##_caller_jmp)) {        \
        func##__real(argv);                     \
      } else {                                  \
        return func##_ret;                      \
      }                                         \
    }                                           \
     else {                                     \
      longjmp(func##_gen_jmp,1);                \
    }                                           \
    return 0;                                   \
  }                                             \
  void func##__real(argt argv)



GENERATOR(int, getNext, int, n) {
  static int counter;

  counter = n;
    while (true) {
        counter = counter+1;
        YIELD(getNext, counter);
    }
}

int main() {
    while (true) {
      int n = getNext(1);
        if (n > 42)
           break;
        printf("%d\n",n);
    }
    return 0;
}