用C实现产量

时间:2013-07-04 21:24:40

标签: 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的所有数字。 我想让yield将getNext的地址更改为yield之后的指令。但我无法弄清楚如何保存上下文(寄存器/变量),因为堆栈将由调用函数运行。

注意:

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

2 个答案:

答案 0 :(得分:12)

即使是在便携式C中,你也可以这样做。这是一个粗略的例子(gcc -Wall gen.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;
}

答案 1 :(得分:2)

您正在寻找的内容被称为“协同程序”,并且(至少不会失去一般性 - 请参阅有限情况下执行此方法的其他答案) portable C.有许多技巧可以伪造它们;请参阅http://en.wikipedia.org/wiki/Coroutine#Implementations_for_C了解几个。