【问题标题】:Technically, can all functions be a void function?从技术上讲,所有函数都可以是 void 函数吗?
【发布时间】:2016-04-28 13:33:41
【问题描述】:

例如:

int f1() {
    return 3;
}
void f2(int *num) {
    *num = 3;
}
int n1, n2;
n1 = f1();
f2(&n2);

使用 f1,我们可以返回一个值并执行“variable=f1()” 但是同样可以使用 void 函数来完成,该函数在给定地址的情况下更新该变量的值,而无需执行“variable=f1()”。

那么,这是否意味着我们实际上可以对所有事情都使用 void 函数?或者有什么是 void 函数无法替代另一个 int 函数/(类型)函数的?

【问题讨论】:

  • 如果你在谈论定义的功能,嗯,或多或少是的。你问来干什么 ?从技术上讲,您可以用汇编代码编写任何程序,但为什么要费心呢?
  • AFAIR main 函数需要返回 int (尽管它是唯一不需要明确返回的函数)。一些库函数也返回值。您不必定义任何要返回的函数,尽管它迟早会导致一些灾难。
  • 如果我们把操作符看作是一种特殊的函数然后不,它们不能是无效的。例如。如果operator + 没有返回右值,则该语言完全无法使用。
  • 你可以。你也可以,写程序从不使用- 操作符,设计一个只有一条指令的CPU,写一部没有字母“e”的小说。这是不切实际的,但可以做到。
  • 是的,但你不能再在表达式中使用它sin(x)*tan(y)-log(z)*exp(t)...

标签: c function


【解决方案1】:

将所有内容都设为 void 函数(在某些人的词典中称为“例程”)的主要问题是你不能轻易地将它们链接起来:

f(g(x))

变成,如果你真的想把它锁起来:

int gout;
f((g(x, &gout), gout))

这很痛苦。

【讨论】:

    【解决方案2】:

    是的,您可以对所有内容使用void 返回类型,并且完全依赖于通过修改后的参数返回。实际上,您可以完全避免使用函数,并将所有内容都放在您的 main 方法中。

    与该语言的任何其他特性一样,返回值会给您带来特殊的优势,您可以自行决定是否需要它们。以下是返回值的一些优点:

    • 可以将返回值分配给const 变量,这可以使您的代码更易于推理
    • 编译器可以对返回值应用某些类型的优化(这更适用于 C++ RVO,但也可能适用于 C 的结构;我不确定)
    • 使用返回值的代码通常更易于阅读,尤其是当函数是数学函数时(例如,假设必须手动声明所有临时函数以使用 sin/cos/etc 进行大型数学运算,如果它们需要通过参数)。比较:

      double x = A*sin(a) + B*cos(b);
      

      double tmpA, tmpB;
      sin(&tmpA, a);
      cos(&tmpB, b);
      double x = A * tmpA + B * tmpB;
      

      或使用与 John Zwinck 在他的回答中建议的类似结构:

      double tmpA, tmpB;
      double x = A * (sin(&tmpA, a), tmpA) + B * (cos(&tmpB, b), tmpB);
      
    • 保证无论函数内部发生什么都会设置该值,因为这是由编译器强制执行的(除了一些非常特殊的情况,例如 longjumps)

    • 您不必担心检查分配的值是否被使用;您可以返回该值,如果请求者不需要它,他们可以忽略它(与在您的替代方法中到处需要 NULL 检查相比)

    当然也有缺点:

    • 你只会得到一个返回值,所以如果你的函数在逻辑上返回多种类型的数据(并且它们不能在逻辑上组合成一个结构),通过参数返回可能会更好
    • 大对象可能会因为需要复制它们而导致性能下降(这就是为什么在 C++ 中引入 RVO 的原因,这大大减少了这个问题)

    【讨论】:

      【解决方案3】:

      那么,这是否意味着我们实际上可以对所有事情都使用 void 函数?

      的确如此。事实证明,这样做是一种相当常见的编码风格。但与void 不同,此类样式通常声明返回值应始终为错误代码保留。

      在实践中,您通常无法始终如一地坚持这种风格。在某些特殊情况下,不使用返回值会变得不方便。

      例如,在编写标准 C 泛型函数 bsearchqsort 使用的回调函数时。期望格式的回调

      int compare (const void *p1, const void *p2);
      

      其中函数返回小于零、大于零或零。在设计方面,保持以只读方式传递的参数很重要,您不希望您的通用搜索算法突然开始修改搜索的内容。因此,虽然理论上没有理由说明为什么这类函数也不能是 void 返回类型,但实际上它会使代码更丑陋且更难阅读。

      【讨论】:

        【解决方案4】:

        当然可以;但这并不是一个好主意。

        它可能并不总是方便或导致易于理解的代码。返回 void 的函数不能直接用作表达式中的操作数。例如,虽然你可以写:

        if( f1() == 3 )
        {
            ...
        }
        

        对于f2(),你必须写:

        f2( &answer ) ;
        if( answer )
        {
            ...
        }
        

        另一个问题是访问控制——通过传递一个指向函数的指针,您可以让该函数间接访问调用者的数据,只要函数表现良好并且不会溢出就可以了。指针可以引用单个对象或对象数组 - 获取该指针的函数必须施加适当的规则,因此它本质上不太安全。

        【讨论】:

        • 关于在表达式中使用 voud 函数@LuizEduardo's 提出了一种方法,但我关于“易于理解的代码”的观点涵盖了这一点。它是有效的,但可能是不正当的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-03-23
        • 1970-01-01
        • 2011-02-21
        • 1970-01-01
        • 2017-02-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多