Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #395462 > unrolled thread

What is the meaning of array parameters?

Started byPhilipp Klaus Krause <pkk@spth.de>
First post2025-11-25 14:28 +0100
Last post2025-12-05 15:36 -0600
Articles 8 — 7 participants

Back to article view | Back to comp.lang.c


Contents

  What is the meaning of array parameters? Philipp Klaus Krause <pkk@spth.de> - 2025-11-25 14:28 +0100
    Re: What is the meaning of array parameters? Michael S <already5chosen@yahoo.com> - 2025-11-25 16:04 +0200
    Re: What is the meaning of array parameters? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-25 13:25 -0800
    Re: What is the meaning of array parameters? Philipp Klaus Krause <pkk@spth.de> - 2025-11-27 10:34 +0100
    Re: What is the meaning of array parameters? antispam@fricas.org (Waldek Hebisch) - 2025-11-29 22:28 +0000
      Re: What is the meaning of array parameters? James Kuyper <jameskuyper@alumni.caltech.edu> - 2025-11-29 22:01 -0500
    Re: What is the meaning of array parameters? Andrey Tarasevich <noone@noone.net> - 2025-12-05 06:01 -0800
    Re: What is the meaning of array parameters? Lynn McGuire <lynnmcguire5@gmail.com> - 2025-12-05 15:36 -0600

#395462 — What is the meaning of array parameters?

FromPhilipp Klaus Krause <pkk@spth.de>
Date2025-11-25 14:28 +0100
SubjectWhat is the meaning of array parameters?
Message-ID<10g4au7$jc8o$1@solani.org>
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

[toc] | [next] | [standalone]


#395463

FromMichael S <already5chosen@yahoo.com>
Date2025-11-25 16:04 +0200
Message-ID<20251125160441.00003007@yahoo.com>
In reply to#395462
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.

[toc] | [prev] | [next] | [standalone]


#395482

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2025-11-25 13:25 -0800
Message-ID<87fra1kdoh.fsf@example.invalid>
In reply to#395462
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 */

[toc] | [prev] | [next] | [standalone]


#395521

FromPhilipp Klaus Krause <pkk@spth.de>
Date2025-11-27 10:34 +0100
Message-ID<10g95vd$mdq5$1@solani.org>
In reply to#395462
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.

[toc] | [prev] | [next] | [standalone]


#395579

Fromantispam@fricas.org (Waldek Hebisch)
Date2025-11-29 22:28 +0000
Message-ID<10gfs2k$1a5el$1@paganini.bofh.team>
In reply to#395462
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.
 
AFAICS there are two essentially different cases: normal arrays,
that decay to pointers and VMT-s which preserve information about
array size.

AFAICS VMT-s were added mostly as a hack, deemed essential in
some application.  But from my point of view definiton was
bothed.  Namely, with size in prototype compiler could spot
at least some cases of discrepancy between call site and
prototype (namly cases when argument in an actual array, so
bound info is available).  And could spot mismatches between
definiton and prototype.  But apparenty standard makers did
not want compilers to check, so they added '*' specifier
which signals VMT-s in prototype, but do no provide bounds
info and (worse) mandated that VMT-s in prototype should be
used as if bound were given as '*'.

However, based on VMT-s one can still add resonably useful
checks to a C compiler.  First, C compier can warn about
anything it wants, so compiler can warn about uses of '*'
in prototypes.  And can warn about mismatches of size info
in prototype and definition and at call site.  Similar
thing is possible using 'static' specifier for fixed
size arrays.  In non-compliant mode compiler can turn
check failures in compile-time errors.

AFAICS checks as above can signifcanty increase number of
memory safe C programs that can be written.  Namely,
with normal compiler one can not use arrays or pointers
in memory-safe programs, as both are unchecked.  With
checking compiler one can safely use visible array, but
one can not pass them between functions, because normal
parameter passing discards array bounds.  Using C-99
parameters one can actually pass arrays and have checking.
OK, checking C-90 compiler could use size info, so could
handle fixed size array.  But VMT-s allow safe passing of
variable sized arrays, which is significant difference.

-- 
                              Waldek Hebisch

[toc] | [prev] | [next] | [standalone]


#395590

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2025-11-29 22:01 -0500
Message-ID<10ggc2g$3vdvf$1@dont-email.me>
In reply to#395579
On 2025-11-29 17:28, Waldek Hebisch wrote:
...
> AFAICS there are two essentially different cases: normal arrays,
> that decay to pointers and VMT-s which preserve information about
> array size.

The term "decay" is often used (though only in one location in the
standard itself) to refer to the consequences of the following rule:

"Except when it is the operand of the sizeof operator, or typeof
operators, or the unary & operator, or is a string literal used to
initialize an array, an expression that has type "array of type" is
converted to an expression with type "pointer to type" that points to
the initial element of the array object ..." (6.3.2.1p3).

This rule applies just as strongly to arrays that have variably modified
type as it does to other arrays.

[toc] | [prev] | [next] | [standalone]


#395684

FromAndrey Tarasevich <noone@noone.net>
Date2025-12-05 06:01 -0800
Message-ID<10guok0$1di0c$1@dont-email.me>
In reply to#395462
On Tue 11/25/2025 5:28 AM, Philipp Klaus Krause wrote:
> 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.

There's one subtle detail when it comes to treatment of such parameters 
in C. It is too little to pass for "motivation"... but it is there.

As you correctly stated, such parameters decay to pointers. However, 
pointers can point to _incomplete_ types, while arrays can only be built 
from _complete_ types. C language happens to insist on the array element 
completeness _before_ adjusting such array parameters to pointers. For 
which reason the following code is invalid:

   struct S; /* incomplete type */

   void foo(struct S s[]) /* ERROR: element type is incomplete */
   {}

(BTW, in C++ the same code would compile without any issues. I believe 
there was an intent to bring C in sync with C++ on that matter, but it 
is still there in C23.)

-- 
Best regards,
Andrey

[toc] | [prev] | [next] | [standalone]


#395685

FromLynn McGuire <lynnmcguire5@gmail.com>
Date2025-12-05 15:36 -0600
Message-ID<10gvj8j$1q6kq$1@dont-email.me>
In reply to#395462
On 11/25/2025 7:28 AM, Philipp Klaus Krause 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

To tell the code reader and the software debugger what the size of the 
array probably is.  Fortran does the same thing.

It is incredibly useful for debugging.

Lynn

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web