我一般都在学习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;
}
答案 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 forms和continuations(以及CPS转化)
是否有任何规则适用于何时使用另一个?
规则是务实的,首先支持源代码的可读性和可理解性。作为经验法则,任何实现数学函数的pure function(如case_one
,数学上为translation)都可以更好地编码为返回某些结果。相反,任何 side effects的程序函数通常被编码为返回void
。对于介于两者之间的案例,请使用您的常识,并查看现有 free software项目中的现有做法 - 他们的源代码 - (例如在github上)。通常副作用procedure可能会返回一些错误代码(或某些成功标记)。阅读printf&amp;的文档scanf提供了很好的例子。
另请注意,许多ABI和calling conventions正在processor registers传递结果(和一些参数)(这比通过内存传递速度快)。
另请注意,C只有call by value。
有些编程语言只有函数返回一个值(有时被忽略或无趣),并且只有表达式,没有任何语句或指令的概念。阅读functional programming。 programming language仅具有值返回功能的一个很好的示例是Scheme,SICP是一本优秀的介绍性书籍(免费提供),我强烈推荐
答案 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提供了一些灵活性。有时不同的方法是等价的,选择一种方法主要是约定,个人风格或本地实践,但对于你给出的例子,第一种选择绝对是首选。