c - GCC 11.2.0 或 Apple Clang 13.0.0 (clang-1300.0.29.30) 关于应用于 VLA 参数的 const 是否正确?

标签 c gcc clang language-lawyer

考虑这个 C 代码:

#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;
}

这是makefile我用过:

# 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 $@

我有两个编译器:

$ 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
$

考虑以下构建记录:

$ 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
$

添加-std=c99 , -std=c11-std=c18不会改变编译错误。使用 Clang 编译时出现的错误 -Weverything选项与 const 无关函数参数的限定符。添加-Wno-vla意味着代码可以在 Clang 下干净地编译(并且 -Werror,-Wpoison-system-directories 错误也会消失)。

如您所见,GCC 提示添加 const到函数的参数,但 Clang 没有。

  • 哪一个是正确的,为什么?

我希望 Clang 是正确的 - 这与我的期望一致。

最佳答案

Which is correct,

海湾合作委员会。

why?

来自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.

该标准有一个明确的规则,允许指针转换 向目标类型添加限定符。

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.

如果目标是数组,则第二条规则不适用,因为 限定符位于元素类型上,而不是数组本身。这导致 使用数组指针时的实际问题。


在 C2X 中 https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf我在 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. [...]

关于c - GCC 11.2.0 或 Apple Clang 13.0.0 (clang-1300.0.29.30) 关于应用于 VLA 参数的 const 是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73356925/

相关文章:

c - 通过 shell 命令获取 C 应用程序的参数

c - 如何向套接字发送信号?

gcc - 迄今为止最稳定的 gcc/g++ 版本

c++ - 为什么std::visit in a unsatisfied concept会导致gcc编译错误

gcc - 使用brew 将 gcc 链接到 gcc-6

c - 我不明白为什么编译器给我这个代码的错误

objective-c - 在 macOS Sierra 上用 clang 编译 Objective-C

c - C 中 < 和 <= 与最大和最小整数的结果不一致

c - 我用于实现 ls 的 C 代码在 Mac 上不起作用

c - 指针运算;最初必须做两次