C++ Logo

std-proposals

Advanced search

Pointers to VLAs as in C99 - (was: Arrays (VLAs) as function parameters (as in C99))

From: Alejandro Colomar (man-pages) <"Alejandro>
Date: Sun, 7 Nov 2021 21:53:23 +0100
Hi Jens,

On 11/7/21 10:15, Jens Maurer wrote:
> On 06/11/2021 22.31, Alejandro Colomar (man-pages) via Std-Proposals wrote:
>> However, VLA syntax for function parameters does not suffer from those
>> issues: it is just syntactic sugar for pointer parameters.
>
> I'm not sure about that. My understanding is that sizeof(param) will
> yield a runtime value in the body of the called function if "param" is
> a VLA.

Hmm, I thought I could hold the other proposal that I had in mind for
just after this one, but maybe it's the other way around.

Regarding what you said, the answer is "it depends". It depends if
we're talking about single-dimension arrays or multi-dimensional arrays.

There are 2 things going on there:

- VLA syntax for pointer parameters
- pointers to VLA

In C, in the case of a single-dimension array in a function parameter,
such as

 int foo(int n, int arr[n]);

it is purely syntactic sugar, as `sizeof(arr)` == `sizeof(int*)` and
*not* `sizeof(int) * n`. And many programmers ignore (or forget) that,
which has caused recurrent bugs. See my StackOverflow answer which
covers that in much more detail (the question was "How do I determine
the size of my array in C?"):
<https://stackoverflow.com/a/57537491/6872717>.
That point also suggests that C2X should add _Lengthof ASAP, but that's
another story.

In the case of multi-dimensional arrays, the size of all except the
outermost array are true arrays; only the outermost array decays to a
pointer. Therefore, in a case such as

 int bar(int l, int m, int n, int md_arr[l][m][n]);

[l] is just syntactic sugar, but [m] and [n] are real dimensions of
subarrays, and therefore `sizeof(md_arr)` == `sizeof(int) * m * n`.


>
>> My proposal is to add VLA syntax to C++, to add compatibility with C
>> headers, and also to have the same self-documentation that C prototypes
>> already have.
>
> Please make sure to include a discussion about the sizeof behavior
> should you choose to write a paper proposing VLA parameters for
> C++.

So, even though "VLA syntax for pointer parameters" and "pointers to
VLA" are separate features which can live without the other, supporting
only single-dimension arrays would be a bit weird, and therefore it
makes more sense to add first pointers to VLA. I'll diverge from the
original thread in this email, and propose that feature too.

I'll put an example here, which uses bsd extensions to simplify error
reporting, and gcc extensions to show pointers to VLA in action (and
also to simplify some code). In some cases, I know there are better C++
alternatives, but this code is meant to compile also in C (and it does).


$ cat vla.c++
#include <bsd/err.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sysexits.h>


#define lengthof(arr) (sizeof(arr) / sizeof((arr)[0]))
#define slengthof(arr) ((ptrdiff_t)lengthof(arr))


int foo(ptrdiff_t m, ptrdiff_t n);


int main(int argc, char *argv[])
{
 if (argc < 3)
  errx(EX_USAGE, "Pass two integers as arguments");

 return foo(atoi(argv[1]), atoi(argv[2]));
}


int foo(ptrdiff_t m, ptrdiff_t n)
{
 int (*vla)[m][n];
 int l;

 vla = (__typeof__(vla)) malloc(sizeof(*vla));

 printf("Size: %2zu\n", sizeof(*vla));
 printf("Length: %2zu\n", lengthof(*vla));
 putchar('\n');

 l = 0;
 for (ptrdiff_t i = 0; i < slengthof(*vla); ++i) {
  for (ptrdiff_t j = 0; j < slengthof((*vla)[0]); ++j)
   (*vla)[i][j] = l++;
 }

 for (ptrdiff_t i = 0; i < slengthof(*vla); ++i) {
  for (ptrdiff_t j = 0; j < slengthof((*vla)[0]); ++j)
   printf("%5i", (*vla)[i][j]);
  putchar('\n');
 }

 l = (*vla)[m - 1][n - 1];
 free(vla);

 return l;
}


$ c++ vla.c++ -Wall -Wextra -Werror -pedantic
vla.c++: In function ‘int foo(ptrdiff_t, ptrdiff_t)’:
vla.c++:26:15: error: ISO C++ forbids variable length array ‘vla’
[-Werror=vla]
    26 | int (*vla)[m][n];
       | ^~~
vla.c++:26:15: error: ISO C++ forbids variable length array ‘vla’
[-Werror=vla]
cc1plus: all warnings being treated as errors


$ c++ vla.c++ -Wall -Wextra -Werror
$ ./a.out 3 4
Size: 48
Length: 3

     0 1 2 3
     4 5 6 7
     8 9 10 11
$ echo $?
11


The reasons for this addition are allowing multidimensional VLA syntax
for old C arrays, which will be useful in combination with the other
proposed feature of allowing VLA syntax as syntactic sugar for pointer
parameters, and will also be useful as a side effect for old code bases
using C-like C++ that use multidimensional malloc()ed arrays (using code
similar to the above example).



Thanks,

Alex


-- 
Alejandro Colomar
Linux man-pages comaintainer; https://www.kernel.org/doc/man-pages/
http://www.alejandro-colomar.es/

Received on 2021-11-07 14:53:27