不兼容的指针类型和常量性

17

我有一个处理静态二维数组的函数,将数组元素视为常数:

void test_function(const char arr[3][3]);

我正在尝试调用以下函数:

char my_var[3][3] = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} };
test_function(my_var);

使用gcc编译(不带任何标志),我收到以下警告:

test.c:9:8: warning: passing argument 1 of 'test_function' from incompatible pointer type
   test_function(my_var);
                 ^
test.c:4:6: note: expected 'const char (*)[3]' but argument is of type 'char (*)[3]'
 void test_function(const char arr[3][3]);
如果我从“test_function”的原型中移除“const”,这个警告就会消失。但这并不是我真正想要的。 当使用clang编译时,同时使用“-pedantic-errors”和“-Wall”,我没有收到任何有关指针不兼容的警告。 我只是想了解为什么gcc在这种情况下会输出这样的警告。 为什么我的指针/数组不兼容?

我想说这是GCC的一个bug——事实上,Clang根本没有产生任何诊断,这让我非常怀疑。顺便说一下,你应该注意到这实际上是一个警告,而不是一个错误(你似乎一直在使用-Werror编译)。 - nneonneo
2个回答

12

GCC按标准实现是正确的,而Clang是错误的。

6.3.2.3/2:

对于任何限定符q,指向非带限定符类型的指针可以转换为指向该类型的带q限定符版本的指针;

看起来很有前途。但要稍等。

6.2.5/26:

派生类型不受从中派生的类型(如果有)的限定符影响。

特别是应用于数组的这个标准规定是不必要的,而且可以很容易地被反转。也就是说,const char[3]可以很容易地成为char[3]的带const修饰符的版本。但它没有。它们只是不同的、不兼容的类型。事实上,在C语言中根本就没有带const修饰符的数组类型,因此你不能有char[3]的const修饰符版本。这就是我们必须遵守的标准。


1
那么为什么gcc在函数以const char[3]作为参数并传递类型为char[3]的变量时不发出警告呢? - Julien Thierry
5
因为作为函数参数的 const char[3] 是一个谎言。它会被默默地视为 const char*。实际参数会被转化为 char*,然后整个过程都由我引用的6.3.2.3/2规则所覆盖。请注意,我只是翻译,没有解释或提供任何其他内容。 - n. m.

6

来自C-FAQ[问题11.10]

在C语言中,如果你必须在除一级间接引用外的其他级别上分配或传递指针,你必须使用显式转换(例如,在此情况下使用(const char ** )),尽管如常,这种转换的需求可能表明一个更深层次的问题,转换并不能真正解决。

在你的情况下:

test_function((const char (*)[3])my_var);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接