• What is the meaning of array parameters?

    From Philipp Klaus Krause@3:633/10 to All on Tue Nov 25 14:28:39 2025
    Since C99 we have four types of array parameters:

    []
    [assignment-expression]
    [static assignment-expression]
    [*]

    But what is their meaning? They're all compatible, they all decay to
    pointers anyway. Only to [static assignment-expression] does the
    standard give a little bit of extra formal meaning, by making it UB when
    a too-short array is passed.

    They exist, they are different types, but the standard does not give
    them meaning (with the exception noted above). So people using them must
    have a motivation beyond what is explicitly stated in the standard, and
    thus an idea of what the meaning of these would or should be.

    Philipp


    --- PyGate Linux v1.5.1
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Michael S@3:633/10 to All on Tue Nov 25 16:04:41 2025
    On Tue, 25 Nov 2025 14:28:39 +0100
    Philipp Klaus Krause <pkk@spth.de> wrote:

    Since C99 we have four types of array parameters:

    []
    [assignment-expression]
    [static assignment-expression]
    [*]

    But what is their meaning? They're all compatible, they all decay to pointers anyway. Only to [static assignment-expression] does the
    standard give a little bit of extra formal meaning, by making it UB
    when a too-short array is passed.

    They exist, they are different types, but the standard does not give
    them meaning (with the exception noted above). So people using them
    must have a motivation beyond what is explicitly stated in the
    standard, and thus an idea of what the meaning of these would or
    should be.

    Philipp


    May be, The Standard could allow (or even recommend?) diagnostic for
    code like below?
    int foo(int prm[2])
    {
    return prm[2];
    }

    Other than that, there is hardly any meaning.



    --- PyGate Linux v1.5.1
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Tue Nov 25 13:25:18 2025
    Philipp Klaus Krause <pkk@spth.de> writes:
    Since C99 we have four types of array parameters:

    []
    [assignment-expression]
    [static assignment-expression]
    [*]

    But what is their meaning? They're all compatible, they all decay to
    pointers anyway. Only to [static assignment-expression] does the
    standard give a little bit of extra formal meaning, by making it UB
    when a too-short array is passed.

    They exist, they are different types, but the standard does not give
    them meaning (with the exception noted above). So people using them
    must have a motivation beyond what is explicitly stated in the
    standard, and thus an idea of what the meaning of these would or
    should be.

    The [] form is of course the simplest, where
    void foo(int param[]);
    is equivalent to
    void foo(int *param);

    You can optionally include bounds information, which the compiler
    quietly ignores (after checking for legality). This is presumably
    intended as documentation for the reader. For example, the time()
    function originally took a pointer to the initial element of an array of
    two ints (since int was only 16 bits and there was no long type). The declaration was something like:
    time(tvec)
    int tvec[2];
    which in more modern C would be:
    int time(int tvec[2]);
    If you provided something other than a pointer to the 0th element of an
    array of two ints, that was just too bad.

    Quietly ignoring bounds information in array-like parameters is not one
    of C's best features.

    See also section 6 of the comp.lang.c FAQ, <https://www.c-faq.com/>.

    The "static" form was added in C99. This is covered in the C99
    Rationale :

    https://www.open-std.org/jtc1/sc22/WG14/www/C99RationaleV5.10.pdf

    The static keyword provides useful information about the intent
    of function parameters.

    It would be a significant advantage on some systems for the
    translator to initiate, at the beginning of the function,
    prefetches or loads of the arrays that will be referenced
    through the parameters. There is no way in C89 for the user to
    provide information to the translator about how many elements
    are guaranteed to be available.

    The [*] syntax defines a VLA parameter (a pointer to the initial element
    of a variable-length array). It can be used only in a prototype that's
    not part of a function definition. An example from cppreference.com :

    void foo(size_t x, int a[*]);
    void foo(size_t x, int a[x])
    {
    printf("%zu\n", sizeof a); // same as sizeof(int*)
    }

    https://en.cppreference.com/w/c/language/array.html

    It's still up to the caller to ensure that the value of x is correct.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.1
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Philipp Klaus Krause@3:633/10 to All on Thu Nov 27 10:34:37 2025
    Looking at clang and gcc diagnostics:

    // Tested via gcc/clang -Wall -pedantic -Warray-parameter -Warray-bounds test.c

    void f(char a[4])
    {
    a[4] = 7; // clang doesn't warn. gcc warns with -O2/-O3 only
    }

    void g(void)
    {
    char a[3];
    f(a); // gcc warns, clang doesn't.
    f(0); // neither gcc nor clang warn
    }

    So apparently passing a null pointer is considered less bad by gcc than passing an array shorter than declared. And clang doesn't care about
    anything here.


    --- PyGate Linux v1.5.1
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)