12

例如:

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 的所有数字。我想将yieldgetNext 的地址更改为之后的指令yield。但是我不知道如何保存上下文(寄存器/变量),因为堆栈会被调用函数运行。

笔记:

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

4

2 回答 2

18

即使在可移植的 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;
}
于 2013-07-05T07:52:23.483 回答
2

您正在寻找的东西被称为“协程”并且(至少并非不失一般性 - 请参阅其他答案以了解在有限情况下执行此操作的方法)在便携式C 中是不可能的。有许多技巧可以用来你可以伪造它们;见http://en.wikipedia.org/wiki/Coroutine#Implementations_for_C有几个。

于 2013-07-05T01:00:54.447 回答