2

Consider this C code:

#include <stdio.h>

static void print_matrix(size_t rows, size_t cols, const int data[rows][cols])
{
    for (size_t r = 0; r < rows; r++)
    {
        const char *pad = "";
        for (size_t c = 0; c < cols; c++)
        {
            printf("%s%3d", pad, data[r][c]);
            pad = "  ";
        }
        putchar('\n');
    }
}

int main(void)
{
    /* Created by: gen_matrix -r 3 -c 5 -L 0 -H 999 -n matrix -E -w 3 -S 0x08C777A9 -i */
    /* Random seed: 0x08C777A9 */
    int matrix[3][5] =
    {
        { 984, 843, 464, 599,  17, },
        { 876, 173, 647,  61, 387, },
        { 138, 245, 718, 981, 629, },
    };
    enum { MATRIX_ROWS = 3, MATRIX_COLS = 5 };

    print_matrix(MATRIX_ROWS, MATRIX_COLS, matrix);

    return 0;
}

This is the makefile I used:

# Makefile to demonstrate inconsistency between GCC 11.2.0 and Apple Clang 13.0.0.

CC = gcc

OFLAGS = -O3
GFLAGS = -g
WFLAG1 = -Werror
WFLAG2 = -Wall
WFLAG3 = -Wextra
WFLAG4 = -pedantic
WFLAG5 = -pedantic-errors
UFLAGS = # Set on command line

WFLAGS = ${WFLAG1} ${WFLAG2} ${WFLAG3} ${WFLAG4} ${WFLAG5}
CFLAGS = ${OFLAGS} ${GFLAGS} ${WFLAGS} ${UFLAGS}

PROG1 = gcc23
FILE.c = ${PROG1}.c

PROGRAMS = ${PROG1}

all: ${PROGRAMS}

${PROG1}:
    ${CC} ${CFLAGS} ${FILE.c} -o $@

I have two compilers:

$ gcc --version
gcc (GCC) 11.2.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ clang --version
Apple clang version 13.0.0 (clang-1300.0.29.30)
Target: x86_64-apple-darwin20.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
$

Consider the following build records:

$ rm -f gcc23
$ make CC=gcc 
gcc -O3 -g -Werror -Wall -Wextra -pedantic -pedantic-errors  gcc23.c -o gcc23
gcc23.c: In function ‘main’:
gcc23.c:29:44: error: pointers to arrays with different qualifiers are incompatible in ISO C [-Wpedantic]
   29 |     print_matrix(MATRIX_ROWS, MATRIX_COLS, matrix);
      |                                            ^~~~~~
make: *** [gcc23] Error 1
$ rm -f gcc23
$ make CC=clang
clang -O3 -g -Werror -Wall -Wextra -pedantic -pedantic-errors  gcc23.c -o gcc23
$ rm -f gcc23
$ make CC=clang UFLAGS=-Weverything
clang -O3 -g -Werror -Wall -Wextra -pedantic -pedantic-errors -Weverything gcc23.c -o gcc23
error: include location '/usr/local/include' is unsafe for cross-compilation [-Werror,-Wpoison-system-directories]
gcc23.c:3:73: error: variable length array used [-Werror,-Wvla]
static void print_matrix(size_t rows, size_t cols, const int data[rows][cols])
                                                                        ^~~~
gcc23.c:3:67: error: variable length array used [-Werror,-Wvla]
static void print_matrix(size_t rows, size_t cols, const int data[rows][cols])
                                                                  ^~~~
3 errors generated.
make: *** [gcc23] Error 1
$

Adding -std=c99, -std=c11 or -std=c18 does not alter the compilation errors. The errors from compiling with Clang's -Weverything option are not related to the const qualifier on the function argument. Adding -Wno-vla means the code compiles cleanly under Clang (and the -Werror,-Wpoison-system-directories error goes away too).

As you can see, GCC complains about the addition of const to the argument to the function, but Clang does not.

  • Which is correct, and why?

I want it to be Clang that's correct — that is consistent with my expectations.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • The code is available in my [SOQ](https://github.com/jleffler/soq) (Stack Overflow Questions) repository on GitHub in the [src/so-7335-6925](https://github.com/jleffler/soq/tree/master/src/so-7335-6925) sub-directory. There is also a variant program, `gcc37.c`, that does not use VLAs at all. It runs into the same error from GCC and not Clang. – Jonathan Leffler Aug 15 '22 at 05:27
  • 2
    It compiles under `gcc -std=c2x` (need gcc > 12.0.0). – Lundin Aug 15 '22 at 12:40

1 Answers1

2

Which is correct,

Gcc.

why?

From https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1923.htm :

In the current C standard, qualifiers are always attached to the element type of an array. It is not possible to declare an array type which is const:

6.7.3(9): If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type.

The standard has an explicit rule which allows conversions of pointers to add qualifiers to the target type.

6.3.2.3(3): For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type; the values stored in the original and converted pointers shall compare equal.

This second rule does not apply if the target is an array, because the qualifier is on the element type - not the array itself. This causes practical problems when using pointers to arrays.


In C2X https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf I see in 6.7.3(10):

10 If the specification of an array type includes any type qualifiers, both the array and the element type is so-qualified. [...]

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Thanks, @KamilCuk. Now we have to track down the decisions based on that document — was it included in C18 (the document is from 2015, so it can't be addressed any earlier than C18), or will it be included in C2x (presumed to be C23 at this stage). Provisionally, it looks like GCC is adhering to the letter of the standard but Clang is more usable. Let's hope this is fixed for compatibility with C++ and for sanity's sake. – Jonathan Leffler Aug 15 '22 at 05:47
  • `will it be included in C2x` Newest gcc even has a message: `error: invalid use of pointers to arrays with different qualifiers in ISO C before C2X [-Wpedantic]`. But I can't find the exact changes for C2X for this... – KamilCuk Aug 15 '22 at 05:48
  • See also the more recent document [https://open-std.org/jtc1/sc22/wg14/www/docs/n2607.pdf](https://open-std.org/jtc1/sc22/wg14/www/docs/n2607.pdf) which is included in the C23 draft standards. This is an update of N1923 (and N2497). – Jonathan Leffler Aug 30 '22 at 16:48