何时从函数返回值,何时使用out参数?

时间:2017-02-25 20:27:22

标签: c

我一般都在学习C语言和编程,而且我不知道何时返回一个值以及何时使用void

是否有任何规则适用于何时使用另一个?

这两种情况有什么区别吗?我知道第一种情况是 使用int(n)的本地副本,第二个使用原始值。

#include <stdio.h>

int case_one(int n)
{
    return n + 2;
}

void case_two(int *n)
{
    *n = *n + 2;
}

int main(int argc, char *argv[])
{
    int n = 5;
    n = case_one(n);
    printf("%i\n", n);

    n = 5;
    case_two(&n);
    printf("%i\n", n);

    return 0;
}

4 个答案:

答案 0 :(得分:3)

使用param而不是返回值还有一个原因 - 错误处理。通常,C中函数调用的返回值(int)表示操作成功。由0值表示的错误。 例如:

#include <stdio.h>

int extract_ip(const char *str, int out[4]) {
    return -1;
}

int main() {
    int out[4];
    int rv = extract_ip("test", out);

    if (rv != 0) {
       printf("Error :%d", rv);
    };
}

此方法在POSIX套接字API中使用,例如。

答案 1 :(得分:1)

  

我正在学习C和编程,我不知道何时返回值以及何时使用void。

没有明确的规则,这是一个意见问题。请注意,您可以按以下方式重新编码case_one

// we take the convention that the first argument would be ...
// a pointer to the "result"
void case_one_proc(int *pres, int n) {
   *pres = n+2;
}

然后是像

这样的代码
 int i = j+3; /// could be any arbitrary expression initializing i
 int r = case_one(i);

等同于

 int i = j+3; // the same expression initializing i
 int r;
 case_one_proc(&r, i);  //we pass the address of the "result" as first argument

因此,你可以猜测你可以用只有void返回函数的等效程序替换任何整个C程序(即只有程序) 。当然,您可能必须引入上面的r等补充变量。

所以你看到你甚至可以避免任何值返回功能。但是,这不是方便的(对于人类开发人员来说,代码和读取其他代码)并且可能不是高效

(实际上你甚至可以创建一个复杂的 C程序,它将任何C程序的文本 - 通过它们的几个翻译单元 - 转换为另一个等效的 C程序没有任何值返回功能)

请注意,在最基本machine code级别(至少在x86和ARM等真实处理器上),一切都是指令,表达式不再存在!您最喜欢的C compiler正在将您的程序(以及实践中的每个 C程序)转换为此类机器代码。

如果您想了解有关此类整体计划转换的更多理论,请阅读A-normal formscontinuations(以及CPS转化)

  

是否有任何规则适用于何时使用另一个?

规则是务实的,首先支持源代码的可读性和可理解性。作为经验法则,任何实现数学函数的pure function(如case_one,数学上为translation)都可以更好地编码为返回某些结果。相反,任何 side effects的程序函数通常被编码为返回void。对于介于两者之间的案例,请使用您的常识,并查看现有 free software项目中的现有做法 - 他们的源代码 - (例如在github上)。通常副作用procedure可能会返回一些错误代码(或某些成功标记)。阅读printf&amp;的文档scanf提供了很好的例子。

另请注意,许多ABIcalling conventions正在processor registers传递结果(和一些参数)(这比通过内存传递速度快)。

另请注意,C只有call by value

有些编程语言只有函数返回一个值(有时被忽略或无趣),并且只有表达式,没有任何语句或指令的概念。阅读functional programmingprogramming language仅具有值返回功能的一个很好的示例是SchemeSICP是一本优秀的介绍性书籍(免费提供),我强烈推荐

答案 2 :(得分:1)

这在很大程度上取决于你想做什么,但基本上你应该使用前者,除非你有充分的理由使用后者。

想一想选择的含义。首先,让我们考虑一下我们为功能提供输入的方式。通常,您提供显式常量,编译时常量或临时数据作为输入:

foo(1);
const int a = 2;
foo(a);
int x = 5;
int y = 5;
foo(x + y);

在所有上述情况中,初始值的来源不是存储结果的可行位置。

接下来,让我们考虑一下我们可能希望如何存储结果。最重要的是,我们可能经常想在其他地方使用结果。使用相同的变量来存储然后传递输入以及存储输出可能是不方便的。但此外,我们经常希望立即使用结果。我们将函数作为更大表达式的一部分来调用:

x = foo(1) + foo(2);

以一种使用指针的方式重写前一行将需要许多不必要的代码 - 这是我们当然不想要的时间和复杂性,当它没有真正购买任何东西时。

那么我们什么时候才能使用指针呢? C函数是按值传递的。每当我们传递任何东西时,都会创建一个副本。然后我们可以处理该副本,并在返回时,它需要再次复制。如果我们知道我们想要做的就是操作某些数据集,我们可以提供一个指针作为处理程序,所有复制的都是存储地址的几个字节。

因此,创建功能的前一种流行方式是灵活的,可以简化使用。后者对于处理对象很有用。

显然有时候我们的输入实际上是一个地址,这是将指针用作函数参数的一个简单的例子。

答案 3 :(得分:0)

第一种方法是首选,您返回一个值。当函数计算多个值时,可以使用第二个。

例如,函数strtol有这个原型:

long strtol(const char *s, char **endp, int base);

strtol尝试将s指向的字符串的初始部分解释为以long表示的base整数的表示形式。它返回带有return语句的转换值,并将指向s中数字后面的字符的指针存储到*endp中。但请注意,此标准函数应返回3个值:转换后的值,更新的指针和成功指示符。

还有其他方法可以返回多个值:

  • 返回结构。

  • 更新收到指针的结构。

C提供了一些灵活性。有时不同的方法是等价的,选择一种方法主要是约定,个人风格或本地实践,但对于你给出的例子,第一种选择绝对是首选。