bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: functions with empty parameter lists


From: Bruno Haible
Subject: Re: functions with empty parameter lists
Date: Mon, 06 Feb 2023 23:48:08 +0100

Paul Eggert wrote:
>  static void
> -init_sh_quoting_options ()
> +init_sh_quoting_options (void)
>  {

Your change prompted me to wonder whether this patch should be generalized,
that is, whether all function definitions with empty parameter lists should
be changed to use this style. Like in the attached patch.

I got doubts because
  * I'm using the style with () in function definitions in many places, and
    neither 'gcc -Wall' nor 'clang -Wall' has warned about it, in many years.
  * The ISO C committee attempts to align C with C++ (e.g. regarding the
    attributes syntax), and in C++ a function declaration or definition with
    () denotes zero arguments.

There were two essential changes in this area in ISO C 23:
  * https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2432.pdf
    1) removed the K&R C syntax for function definitions
         int foo (x, y) int x; long y; { ... }
    2) in function definitions, () is equivalent to (void).
  * https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2841.htm
    3) A function declarator with a parameter list of () declares a prototype
       for a function that takes no parameters (like it does in C++).
       See ISO C 23 ยง 6.7.6.3.(13).

For those of us that are not standards experts, the effects can be seen
through two test cases, with clang 15.0.6.

=================================== foo1.c ===================================
#include <stdio.h>

void func();

int main() {
    func("AAA");
    return 0;
}

void func() {
    printf("in func()\n");
}
=================================== foo2.c ===================================
#include <stdio.h>

void func() {
    printf("in func()\n");
}

int main() {
    func("AAA");
    return 0;
}

==============================================================================

clang diagnostics for older standard versions:

$ clang -Wall foo1.c
foo1.c:6:9: warning: passing arguments to 'func' without a prototype is 
deprecated in all versions of C and is not supported in C2x 
[-Wdeprecated-non-prototype]
    func("AAA");
        ^
1 warning generated.
$ clang -Wall foo2.c
foo2.c:8:15: warning: too many arguments in call to 'func'
    func("AAA");
    ~~~~      ^
foo2.c:8:9: warning: passing arguments to 'func' without a prototype is 
deprecated in all versions of C and is not supported in C2x 
[-Wdeprecated-non-prototype]
    func("AAA");
        ^
2 warnings generated.

clang diagnostics for C23:

$ clang -std=gnu2x -Wall foo1.c
foo1.c:6:10: error: too many arguments to function call, expected 0, have 1
    func("AAA");
    ~~~~ ^~~~~
foo1.c:3:6: note: 'func' declared here
void func();
     ^
1 error generated.
$ clang -std=gnu2x -Wall foo2.c
foo2.c:8:10: error: too many arguments to function call, expected 0, have 1
    func("AAA");
    ~~~~ ^~~~~
foo2.c:3:6: note: 'func' declared here
void func() {
     ^
1 error generated.


What does this mean?

(I) In function *definitions*, () and (void) mean the same: zero arguments.
    This was always the case, in C89, in K&R C, and equally in C++.

(II) Regarding function *declarations*, this gives a whole new view of the
     history.

     * In C23, () and (void) mean the same: zero arguments. It's like this
       in C++ as well, for many years.

     * The (void) syntax was only introduced as a temporary workaround,
       as long as - in C only, not in C++ - () in function declarations meant
       a varargs list: (...).

     * The GCC warning -Wstrict-prototypes is a migration aid, whose purpose
       is to remind the programmer to convert declarations such as
         void func ();
       to either
         void func (void);
       or
         void func (first_t arg, ...);

       Unfortunately, this GCC warning also warns about function definitions
         void func () { ... }
       although there was never a need to warn about these; see (I) above.

(III) So, why is (void) allowed in function *definitions* at all?
      I can only guess:
        - Maybe the future standardization path of this area was not clear
          in 1989. (For instance, C++ did not exist at that time, and nowadays
          ISO C is following ISO C++ in some aspects.)
        - There was the desire to have the same syntax across function
          declarations/types and function definitions.

Now, how should we go ahead in this situation? This is my opinion:

  * In the long term, assuming ISO C 23 and newer, writing (void) is just
    clutter in those places where one can just as well write (). The keyword
    'void' here only tells that the programmer has accomplished the migration
    from K&R C to ISO C 23, nothing else.

  * We can assume that the readers and contributors of our code know the
    difference between a function declaration/type and a function definition.
    Therefore, I'm in favour of turning all (void) in function *definitions*
    to ().
    This can happen now or any time.

  * We should stop compiling with -Wstrict-prototypes and instead (not always,
    but frequently enough) compile with the '-std=gnu23' option. Clang
    currently implements it better. GCC 13 may be on par with clang again on
    this topic [1].

  * We need to continue to use (void) in function declarations/types, as long
    as we support compilers for ISO C standards before C 23. This will
    probably take 10 or 15 years.

Bruno

[1] https://gcc.gnu.org/gcc-13/changes.html

Attachment: use-void-parameter-lists-in-function-definitions.diff
Description: Text Data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]