在文章 <1992Aug3.070036.20027@cucs5.cs.cuhk.hk> 中,wong yick pong 写道:
> 我正在写一个库,其中一个函数应该返回一个字符串
> 但这个[例程倾向于返回]……(垃圾)。
> 这是因为 test 是一个局部变量吗?
> 我知道我可以使用 static char 或将 test 声明为全局变量,
> 但第一种方法会使代码不易理解,
> 而第二种方法在库中是不可行的。
我不确定使用 static 为什么会使代码更难理解;这是流行且推荐的解决方案之一。
我知道至少有九种不同的方法可以在 C 中从子例程返回聚合数据(即结构和数组,包括字符串),尽管其中一种不起作用,两种是组合,一种是开玩笑的。
我听说第 5 种是 GNU 项目的最爱。我非常喜欢第 8 种,尽管我并不经常使用它。
第 2 和第 3 种显然是最简单安全的选项,尽管它们对调用者来说需要更多工作。两者之间,第 2 种大多数时候都很好;第 3 种适用于调用者无法很好地估计所需返回缓冲区大小时(且所有数据都必须一次性返回),或者当调用者很可能调用 malloc 并存储多个返回值的副本时,并且动态内存分配的开销和其他轻微缺点不成问题时。
第 4 种,虽然可能令人烦恼且容易出错,但在某些情况下也很好,显然是指调用者不太可能同时需要使用多个返回值的情况。ctime()是一个很好的例子——它最常见的用途是打印当前时间,并且在任何给定时刻只有一个当前时间,调用者不太可能需要维护多个独立的返回值。
第 5 和第 6 种显然是想两全其美,有时是合适的,但可能导致不必要的复杂性和混淆(也就是说,不够成熟的程序员可能会对例程文档中关于其多种个性的讨论感到困惑)。这些技术可能应该谨慎使用,仅在真正需要极高的灵活性且主要由经验丰富的程序员使用该例程时使用。
第 7 种是一种完全足够的解决方案,它不像它本可以的那样被广泛了解和使用,因为许多人认为结构在 C 中是“二等公民”,因为根据 K&R1 它们是,尽管 Ritchie 在 K&R1 发布时的 C 编译器,以及之后的所有高质量 C 编译器,以及所有 ANSI C 编译器,都完全支持结构赋值、传递和返回。
请注意,如果我们有
extern struct blort blortfunc(); f() { struct blort blort1, blort2; blort1 = blortfunc(1); blort2 = blortfunc(2); ... }
结构返回和赋值给两个局部结构变量,使我们能够同时操作两个聚合返回值,而不会发生冲突(即不会发生“每次调用数据都被覆盖”),并且无需手动分配或取消分配。
第 8 种是一种鲜为人知的技术,是我某天自己发明的,尽管我在网上见过一两次提及,所以其他人显然也想到了。这是一种稍微复杂的技术,在新手程序员在场的情况下使用可能会令人困惑,但在特定情况下可能非常有用。我只将其用于字符串格式化例程之类的操作,这些例程可以生成其他数据结构的打印字符串表示,并且在单次调用(例如)期间很可能被使用一次以上printf。例如,假设我有
char *roman(int);返回一个整数的罗马数字表示int。我可能想做这样的事情
printf("%s + %s = %s\n", roman(12), roman(34), roman(12 + 34));现在,如果我使用技术 2,它看起来会像
char buf1[20], buf2[20], buf3[20]; printf("%s + %s = %s\n", roman(12, buf1, 20), roman(34, buf2, 20), roman(12 + 34, buf3, 20));
,这是一团糟。如果我使用技术 3,它看起来会像
char *p1, *p2, *p3; printf("%s + %s = %s\n", p1 = roman(12), p2 = roman(34), p3 = roman(12 + 34)); free(p1); free(p2); free(p3);
,这也很糟糕。
这显然是技术 4 崩溃的那种情况,尽管你当然可以这样做
printf("%s + ", roman(12)); printf("%s = ", roman(34)); printf("%s\n", roman(12 + 34));
但是如果我使用技术 8,并且如果roman()的实现保证至少有 3 个独立的静态返回缓冲区,那么我实际上可以编写显而易见的
printf("%s + %s = %s\n", roman(12), roman(34), roman(12 + 34));并且它会工作得很好。
技术 8 的实现看起来大致如下
#define NRETBUFS 3 #define RETBUFSIZE 20 char *roman(n) int n; { static char retbufs[NRETBUFS][RETBUFSIZE]; static int whichret = 0; char *ret; ret = retbufs[whichret]; whichret = (whichret + 1) % NRETBUFS; now format answer into ret... return ret; }
我不再讨论技术 9。
Steve Summit