在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;
}