有效的多个返回值[重复]

Posted

技术标签:

【中文标题】有效的多个返回值[重复]【英文标题】:Effective multiple return values [duplicate] 【发布时间】:2014-01-21 14:43:54 【问题描述】:

假设我们有一个应该返回两个返回值的函数。 例如,我们有一些函数返回 char* 及其长度。 Char 是在该特定函数中分配的。

我可以想象以下方法:

int foo(char **result);       // Passing pointer to char*, returning int
char* bar(int *len);          // Passing pointer to int, returning char*
struct char_and_len foobar(); // Returning struct that contains both values

还有其他方法可以实现多个值吗?最有效的方法是什么?

考虑到性能、内存对齐或任何其他隐藏的 C 功能,我非常感谢详细的解释。

【问题讨论】:

为什么比您提供的选项更聪明?这样做只会混淆你的代码。 @meagar。为什么?我很好奇这样做的其他方法是什么。这样做可能有一些非常有趣的原因。此外,我有强烈的感觉,在 C 中做同一件事的不同方式可能会产生不同的效果和考虑。 【参考方案1】:

这里有两种情况。如果您使用的代码库/框架(例如 Glib)具有贯穿整个应用程序的标准字符串结构,请使用第三个选项:

struct string function();

如果您的代码库没有在任何地方都使用一个标准结构作为字符串,我建议不要使用结构。来回转换的麻烦并不值得。

否则,约定(至少我见过)是返回 char* 并将长度作为指针参数:

char* function(int* length);

【讨论】:

请您详细说明为什么char* f(int*) vs int f(char **) @Sigurd:至少在我见过的大多数代码和库函数中,char** 用于调用者负责内存分配并且已经确定了长度,或者正在提供一个最大长度。例如,在 Linux 系统调用 read(2) 中,您提供了一个预分配的缓冲区和该缓冲区的最大数据长度。 "否则,约定是返回 char* 并将长度作为指针参数:" -- 断言约定 is 这有点苛刻。还有其他同样有效的约定。 @H2CO3:是的。见编辑。【参考方案2】:

另一种方式:

void foo(char **result, int *len);

我认为最糟糕的是:

struct char_and_len foobar();

我更喜欢我给你看的那个,因为我不喜欢在参数和有效返回中混合返回值。

【讨论】:

【参考方案3】:

您可以只返回一个数组并将其包装在一个结构中:

typedef struct 
    char *strings[2];
 RetType;

RetType func()

    return (RetType)  "foo", "bar"  ;

另一个惯用的解决方案是 C 将数组传递给您的函数并填充它:

void func(char *strings[2])

    strings[0] = "foo";
    strings[1] = "bar";

第三种解决方案是返回一个值并通过指针传递另一个值(尽管如果您有不同类型的值,这更有意义):

char *func(char **outparm)

    *outparm = "foo";
    return "bar";

另外,请原谅我没有const-正确。

【讨论】:

我的问题可能不太清楚。我需要返回 int 和 char *。假设 char 没有以 \0 结尾,所以我们必须返回它的长度。 @Sigurd 然后您可以将struct 更改为包含char *int。您也可以将第三个示例中的返回值之一更改为int。忘记第二种方法。 我知道如何返回多个值 :) 我的问题是什么是最有效的方法以及为什么。 @Sigurd 在什么意义上有效?我列出了所有实际可行的解决方案。选一个。真的没关系。【参考方案4】:

我最喜欢的是

void foobar(struct char_and_len*);

出于以下原因:

只需要传递一个参数 返回值/输出参数不混 可以忽略返回值,尤其是在需要再次释放返回值时,这可能是编程错误的严重来源。输出参数不可忽略。 拥有指向结构的指针可避免过多的复制操作。只需向函数提供一个指针。 这样,函数的调用者可以决定 struct char_and_len 的存储位置(在堆、堆栈上),而在使用返回值时,数据至少需要暂时放入堆栈

【讨论】:

如果您为此目的制作了一个结构,为什么不按值返回整个结构。 虽然总的来说我同意你的观点,因为我们在这里处理字符串,你不认为定义一个必须相互转换的字符串“类型”是个问题吗? 【参考方案5】:

使用字符串。

对于您引用的具体示例,请记住长度隐式或显式是任何字符串类型的属性。例如,C 风格的字符串是以 null 结尾的,所以即使没有明确的长度,调用者仍然可以确定字符串的长度。 Pascal 风格的字符串包括长度作为第一个字节。 char* 不一定是字符串,它可能是您确实需要长度的普通旧文本缓冲区。但是字符串类型的重点是避免需要单独传递数据和长度。

更一般地...

一个函数只能返回一个值,所以如果你需要返回更多的值,你需要使用结构将所有内容打包成一个值,或者传递一个(或多个指针)到接收结果的位置。您使用哪种方法取决于具体情况。您是否已经为需要返回的数据定义了一个结构?调用者是否可能有一个可以接收结果的现有对象?没有最好的方法,只有适合的方法。

【讨论】:

【参考方案6】:

最好的方法是始终使用指针。在 C 中,每个函数都复制在不同内存区域中传递的参数。最好的方法是您在性能方面发布的三个中的第二个。

但我会将一个指向结构的指针作为参数传递,该结构包含长度和字符串,并返回 void。

【讨论】:

C 中的字符串始终是指针,无论您是通过引用还是值传递指针本身。 是的,但他也有一个 int。 一个 int 通常是四个字节。在 32 位系统上,指针也是如此。在 64 位系统上,指针(8 字节)实际上会大于int 在 64 位系统上 int 和 *int 具有相同的大小,4 个字节而不是 8 个。我刚刚检查过(在 32 位系统上它是 2 个字节)。因此,在这种情况下,您不会注意到性能有任何改进:P 出于这个原因,我说我会使用一个指向其中包含两种数据类型的结构的指针。【参考方案7】:

在 C 中,返回两个值是不“正常的”。这意味着正如您已经做的那样,您可以创建一个结构来返回结果。这是形式上正确的方法,但不是最简单的方法,而且很麻烦。所以我会完全忘记那个解决方案。

通常,返回结果的另一种方式是通过引用传递参数(在 Pascal VB 等中)。 在 C 中,不可能通过引用传递它们,而是传递一个指针。 但在 C++ 中,可以通过引用传递变量(这意味着传递指针但使用变量)。

所以我相信做你需要的最简单的方法是定义:

char* bar(int *lenP); //

现在你有了一个可以返回两个结果的函数的结果:

如果它被定义为伪语法 (s,l)=bar();

此外,您还可以使用:

空条(char * *s,int * lenP); // 这种情况同样对待 too 参数。

在 C++ 中,我会使用按引用的方法,因为虽然从实际角度(处理器的作用)来看是相同的,但它对程序员来说更简单。

【讨论】:

以上是关于有效的多个返回值[重复]的主要内容,如果未能解决你的问题,请参考以下文章

从函数返回多个值[重复]

从c#中的方法返回多个值[重复]

从python 3.5中的函数返回多个值[重复]

我如何从c ++中的函数返回多个值[重复]

jQuery使用同一类的多个按钮返回一个值[重复]

从函数调用分配多个返回值的性能[重复]