【问题标题】:How can a function "remember" it's result for its next use?函数如何“记住”它的结果以供下次使用?
【发布时间】:2015-02-22 18:02:02
【问题描述】:

如何创建一个记住其返回结果的函数?

例如:

char * foo(char * str1, char * str2){
   ...
   return bar;
}

int main(){
  ...
  foo(a,b);   //returns a string
  foo(NULL,c);//will use the returned above string in the NULL parameter
}

这类似于strtok 的工作方式。

我想全局变量可以工作,但据我所知这不是好的做法,还有其他方法吗? strtok 是否与全局变量一起使用?

【问题讨论】:

  • 为什么不捕获返回并在第二次调用中将其传递给函数?
  • strtok() 通常使用static 变量实现,这与全局变量一样糟糕。
  • foo(foo(a,b),c);一样称呼它
  • @SMA 如果我想让它循环工作怎么办?
  • 以问题的形式回答:What does “static” mean in a C program?.

标签: c function syntax


【解决方案1】:

这就是 C 中的 static 关键字的用途。 有点!请注意,请参阅下面的修改。

具有static 存储类的变量将在程序的生命周期内存在,而不仅仅是声明范围的末尾:

int foo()
{
    static int counter = 0;
    counter ++;
    return counter;
}

将在连续调用时返回1,2,3...

编辑:评论者似乎同意警告您static 是危险的,如果您正在进行并发访问(即多线程),我同意这一点。但是话又说回来,您已经意识到全局变量可能是有害的,所以这可能不是新的,并且考虑到您的问题的性质,您可能还没有在您的编程生涯中进行多线程处理;如果您正在这样做,请参阅向您介绍多线程的任何内容,以获取修改共享状态(信号量/互斥体...)的安全方法。

EDIT2:这当然不仅在多线程环境中是危险的;例如,当两个不同的函数在内部调用foo,并期望看到它们自己的1,2,3... 序列时,事情就会出错。使用时要格外小心。

EDIT3:尽管如此,@sashoalm 的答案是正确的,并且最适合您的问题的标题。 static 更适用于不可变的、一次性可初始化的状态,而不是用于在几乎任何环境中都可能起火的可修改事物。所以在这里我引用最重要的一行of the best answer,因为你已经决定接受我的回答,这可能会误导后来的读者:

所以最正确的答案是不,你不能在 C 中这样做,不,静态不是答案。

【讨论】:

  • 这是一个正确的答案,但值得一提的是,static 局部变量并不比可变全局变量好多少:它们唯一的区别是作用域。 static locals 仅限于函数的作用域,这很方便。它们与可变全局变量一样是线程不安全的。
  • 或者更好_Thread_local。取决于用例。
【解决方案2】:

我正在回答您的标题,即“函数如何“记住”它的结果以供下次使用?”。您的标题暗示了一般情况,我对您问题正文中的特定功能不感兴趣。

首先,我要对 Python 的 yield 关键字表示敬意,不幸的是,在 C 中没有这样的语法糖。

所以最正确的答案是不,你不能在 C 中这样做,不,静态不是答案

静态不可重入。有时一个简单的不,你不能这样做,不是真的,不是在 C 中,比告诉你半生不熟的解决方案要好。 C 只是没有这个特性,仅此而已。

Python 有 yield,C 没有。结束。

你必须通过使用结构来模拟它来保存状态。

一些伪代码:

struct State { ... };
Output foo(struct State *state, ...) { ... }

...

foo(&state);
foo(&state);

如果您不想以正确的方式执行此操作,请在尝试嵌套调用该函数时使用静态并花 2-3 天时间找出错误。 strtok 就是这样咬人的。

注意,使用static 可能会使函数不可重入。小心:

Output foo(...) { static struct State state; ... }

附录

数学意义上的函数根据定义是无状态的。如果它有状态,那么它是一个对象,而不是一个函数。具有静态状态的函数在语义上实际上是一个单例对象。

状态意味着内存,而内存+方法=对象。

【讨论】:

  • 这绝对不会让函数记住自己的状态,而是让程序员在外面处理它;它非常 C,基本上是启发人们编写 C++ 的原因,有时它非常很方便,但这并不是不想作为foo 的调用者处理状态的答案。跨度>
  • 不可重入是什么意思?
  • @MarcusMüller Well C 只是没有这个功能。 static 只是听起来像是他想要的,但实际上不是他想要的并且会咬他。这是一个假状态,因为它是一个用于所有实际目的的全局变量。它不是可重入的。
  • @sashoalm:是的。但这正是他所要求的——我在我的答案中添加了第二个编辑,希望这会警告他。另外,由于你的回答对来世更有用,我认为我应该给你我的支持:)
  • @MarcusMüller 我讨厌标题和正文之间不一致的问题。如果标题是通用的,例如“函数如何“记住”它的结果以供下次使用?”我想问题就是这样。我并不真正关心他的特殊功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-27
  • 1970-01-01
  • 2020-08-26
  • 2012-01-06
  • 2018-03-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多