Re: [PATCH] Various pages: SYNOPSIS: Use VLA syntax in function parameters

Alejandro Colomar
2022-09-03T15:09:25Z

[-- Attachment #1.1: Type: text/plain, Size: 3878 bytes --]

Hi Martin,

On 9/3/22 16:35, Martin Uecker wrote:
> Am Samstag, den 03.09.2022, 15:41 +0200 schrieb Alejandro Colomar:
>> Hi Martin,
>>
>> On 9/3/22 14:47, Martin Uecker wrote:
>> [...]
>>
>>> GCC will warn if the bound is specified inconsistently between
>>> declarations and also emit warnings if it can see that a buffer
>>> which is passed is too small:
>>>
>>> https://godbolt.org/z/PsjPG1nv7
>>
>> That's very good news!
>>
>> BTW, it's nice to see that GCC doesn't need 'static' for array
>> parameters. I never understood what the static keyword adds there.
>> There's no way one can specify an array size an mean anything other than
>> requiring that, for a non-null pointer, the array should have at least
>> that size.
>
> From the C standard's point of view,
>
> void foo(int n, char buf[n]);
>
> is semantically equivalent to
>
> void foo(int, char *buf);
>
> and without 'static' the 'n' has no further meaning
> (this is different for pointers to arrays).

I know. I just don't understand the rationale for that decission. :/

>
> The static keyword implies that the pointer is be valid and
> non-zero and that there must be at least 'n' elements
> accessible, so in some sense it is stronger (it implies
> alid non-zero pointers), but at the same time it does not
> imply a bound.

That stronger meaning, I think is a mistake by the standard.
Basically, [static n] means the same as [n] combined with [[gnu::nonnull]].
What the standard should have done would be to keep those two things
separate, since one may want to declare non-null non-array pointers, or
possibly-null array ones. So the standard should have standardized some
form of nonnull for that. But the recent discussion about presenting
nonnull pointers as [static 1] is horrible. But let's wait till the
future hopefully fixes this.

>
> But I agree that 'n' without 'static' should simply imply
> a bound and I think we should use it this way even when
> the standard currently does not attach a meaning to it.

Yep.

[...]

>> What about taking something from K&R functions for this?:
>>
>> int foo(q; w; int a[q], int q, int s[w], int w);
>>
>> By not specifying the types, the syntax is again short.
>> This is left-to-right, so no problems with global variables, and no need
>> for complex parsers.
>> Also, by not specifying types, now it's more obvious to the naked eye
>> that there's a difference:
>
> I am ok with the syntax, but I am not sure how this would
> work. If the type is determined only later you would still
> have to change parsers (some C compilers do type
> checking and folding during parsing, so need the types
> to be known during parsing) and you also still have the
> problem with the mutual dependencies.

This syntax resembles a lot K&R syntax. Any C compiler that supports
them (and I guess most compilers out there do) should be easily
convertible to support this syntax (at least more easily than other
alternatives). But this is just a guess.

>
> We thought about using this syntax
>
> int foo(char buf[.n], int n);
>
> because it is new syntax which means we can restrict the
> size to be the name of a parameter instead of allowing
> arbitrary expressions, which then makes forward references
> less problematic. It is also consistent with designators in
> initializers and could also be extend to annotate
> flexible array members or for storing pointers to arrays
> in structures:

It's not crazy. I don't have much to argue against it.

>
> struct {
> int n;
> char buf[.n];
> };
>
> struct {
> int n;
> char (*buf)[.n];
> };

Perhaps some doubts about how this would work for nested structures, but
not unreasonable.

Cheers,

Alex

--
Alejandro Colomar