【问题标题】:Why a function with no arguments works, but a function with void as argument doesn't?为什么没有参数的函数可以工作,而以 void 作为参数的函数却不能?
【发布时间】:2020-10-03 01:31:08
【问题描述】:

在下面的代码中,我使用main() 外部的函数计算PI。两者的唯一区别是:

  • 第一个代码。我没有传递任何参数:void calculate_pi ();
  • 第二个代码。我明确表示没有要传递的参数:calculate_pi (void);

我原以为第二个更好,但似乎并非如此。为什么是这样?谢谢!

第一个代码:

#include <stdio.h>
#include <stdlib.h>

void calculate_pi ();

int main(void)
{

    calculate_pi ();

    return 0;
}

void calculate_pi ()
{
    int i, signo;
    double pi_approx = 1, pi_final;

    for (i = 1; i < 1000000; ++i)
        {
            signo = (i%2) ? -1 : 1;
            pi_approx = pi_approx + (float) signo / (2*i+1);
        }

    pi_final = pi_approx * 4;
    printf("%.10f\n", pi_final);
}

第二个代码:

#include <stdio.h>
#include <stdlib.h>

void calculate_pi (void);

int main(void)
{

    calculate_pi (void);

    return 0;
}

void calculate_pi (void)
{
    int i, signo;
    double pi_approx = 1, pi_final;

    for (i = 1; i < 1000000; ++i)
        {
            signo = (i%2) ? -1 : 1;
            pi_approx = pi_approx + (float) signo / (2*i+1);
        }

    pi_final = pi_approx * 4;
    printf("%.10f\n", pi_final);
}

【问题讨论】:

  • the second one is better 第二个编译和工作? I am explicitly saying there are no arguments to pass 不,你不是,void 并不意味着在函数调用中。这意味着在 函数声明.
  • 感谢您的快速回答@KamilCuk 我根据您的评论在正确的代码下方添加了!谢谢!

标签: c function arguments parameter-passing void


【解决方案1】:

用空参数列表声明函数,如void calculate_pi();,是一种旧的 C 语法,它没有指定参数类型。在新代码中应该避免它。最好使用参数列表声明函数,例如int foo(char *x);。新语法提供了更好的类型信息,并允许编译器检查参数类型并提供有用的警告和错误消息。

由于 C 使用 () 来声明没有参数类型规范的函数,因此需要使用不同的语法来指定函数具有 no 参数。根据 C 2018 6.7.6.3 10,采用 (void) 作为特例来表明这一点:

void 类型的未命名参数作为列表中唯一项的特殊情况指定该函数没有参数。

因此,声明void calculate_pi(void); 并不表示calculate_pi 接受void 参数;它说calculate_pi 没有任何参数。这是声明没有参数的函数的首选方式。

由于该函数不接受参数,因此应该不带参数调用它,使用calculate_pi()

calculate_pi(void) 不是有效的 C 表达式。函数参数必须是值,但void 是类型,类型void 不能作为函数参数出现。所以现代 C 中的首选代码是声明函数不带参数:

void calculate_pi(void);

并在没有参数的情况下调用它:

calculate_pi();

【讨论】:

    【解决方案2】:

    在函数的声明/定义中将void用作参数类型与在实际调用函数时用作参数是不同的。

    void 在这种情况下只能用作参数,而不能用作函数调用中的参数。无论如何都不应使用void 类型的表达式,因为它实际上根本不会产生任何值。否则程序调用undefined behavior

    “无论如何都不应使用 void 表达式(具有 void 类型的表达式)的(不存在的)值,并且不应将隐式或显式转换(除了 void)应用于此类表达式。如果表达式任何其他类型的被评估为 void 表达式,其值或指示符被丢弃。(评估 void 表达式的副作用。)"

    来源:C18,6.3.2.2/1

    您需要将calculate_pi 称为calculate_pi() 而不是calculate_pi(void)

    int main (void)
    {
        calculate_pi();
    
        return 0;
    }
    

    我本以为第二个更好,但似乎并非如此。

    在声明/定义中使用void 确实比使用空参数列表更好,因为带有空参数列表的声明严格地被视为不是原型。

    C 标准状态(强调我的):

    “对于标识符指定的每个不同实体,标识符仅在称为其范围的程序文本区域内可见(即可以使用)。由相同标识符指定的不同实体具有不同的范围,或者位于不同的范围内命名空间。有四种作用域:函数、文件、块和函数原型。(函数原型是声明其参数类型的函数的声明。)"

    因此,如果您指定一个空参数列表,例如 f.e.,某些编译器会发出警告。 Clang 会:

    "警告:此函数声明不是原型 [-Wstrict-prototypes]"

    但在这种情况下,问题出在其他地方,如上所述。


    旁注:

    • 如果您默认提供void 作为参数,编译器通常会抛出错误,因此您的代码甚至不应该被编译。请考虑换用最新且符合标准的编译器,例如 GCC 或 Clang。

    【讨论】:

      【解决方案3】:

      最好使用第一个代码,因为您已经将 calculae_pi() 函数的返回类型指定为 void。不必像在第二个代码中那样放置 void。

      【讨论】:

        【解决方案4】:

        根据@KamilCuk 的评论,正确的代码应该是这样的:

        #include <stdio.h>
        #include <stdlib.h>
        #define PI 3.14159265359
        
        void calculate_pi (void);
        
        int main(void)
        {
        
            calculate_pi ();
        
            return 0;
        }
        
        void calculate_pi (void)
        {
            int i, signo;
            double pi_approx = 1, pi_final;
        
            for (i = 1; i < 1000000; ++i)
                {
                    signo = (i%2) ? -1 : 1;
                    pi_approx = pi_approx + (float) signo / (2*i+1);
                }
        
            pi_final = pi_approx * 4;
            printf("%.10f\n", pi_final);
        }
        

        【讨论】:

        • 答案应该包含答案。显示没有解释的代码不是答案。参考评论不是答案;解释应该在答案本身中。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-07-03
        • 1970-01-01
        • 1970-01-01
        • 2019-04-18
        • 1970-01-01
        • 2014-10-14
        • 1970-01-01
        相关资源
        最近更新 更多