为什么当我在带有常量参数的函数中传递二维数组时收到警告,而在一维中一切正常?
Why I got a warning when I pass 2D array in function with constant parameter whilst in 1D everything is normal?
我有以下两个相似的代码
片段 1:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define W 5
#define N 9
void print_w(const char x[W] [N+1]);
int main()
{
char words[W][N + 1]={{}};
print_w(words);
printf("R*E*V*E*R*E*S*E\n");
print_w( (const char (*) [N+1]) words);
return 0;
}
void print_w(const char x[W] [N+1]){
int i;
for (i=0; i<W; i++) {
printf("Word (%d) :%s\n", i, x[i]);
}
return;
}
片段 2:
#include <stdio.h>
#include <stdlib.h>
#define N 9
void printString(const char []);
int main(){
char mystr[N + 1];
scanf("%9s", mystr);
printString(mystr);
printString( (const char (*) ) mystr);
return 0;
}
void printString(const char str[]){
int i;
for (i=0; str[i]!=0; i++) {
printf("%c\n", str[i]);
}
}
在片段 1 中,我收到一条警告,告诉我在行 print_w(words);
:
[Warning] passing argument 1 of 'print_w' from incompatible pointer type
暗示我必须在 print_w( (const char (*) [N+1]) words);
中进行类型转换
虽然在代码片段 2 中,我的代码并非如此,因为我在没有警告的情况下执行了这两个选项。
为什么第一个示例中有警告,而第二个示例中没有?我想在函数中传递错误的变量类型 (char --> const) 并非如此,因为在片段 2 中也会出现警告。
这是C标准的缺陷;指向 char
数组的指针与指向 const char
数组的指针不兼容,并且可能无法(通过定义的行为)作为指向 const char
.
注意,数组自动转换后,print_w(words)
传递的是数组指针给print_w
,不是数组的数组,而且,数组参数自动调整后,void print_w(const char x[W] [N+1])
声明 printString
具有指向数组的指针类型的参数,而不是数组的数组。所以我们关心的是数组指针的规则。
对于char (*)[N+1]
和const char (*)[N+1]
,我们首先考虑这些指针类型是否兼容。根据 C 2018 6.7.6.1 2,要使两个指针类型兼容,它们必须指向兼容的类型。
它们指向数组,所以我们看 6.7.6.2 6,它说,要使两种数组类型兼容,两者都应具有兼容的元素类型。
对于元素,我们看 6.7.3 11,它说,对于要兼容的两个限定类型,两者都应具有兼容类型的相同限定版本。 char
和const char
不是全等限定,所以不兼容,所以数组类型不兼容,所以指针类型不兼容。
如果允许对参数类型进行赋值,则函数调用允许传递参数的实参,根据 C 6.5.2.2 2。根据 6.5.16.1 1,赋值允许向 pointed-to 类型“添加”限定符.例如,指向 char
的指针可以分配给指向 const char
的指针。这就是 void printString(const char [])
代码不产生错误或警告消息的原因。但是,规则不允许在类型中更深地添加限定符。因此,指向 char
数组的指针不能分配给指向 const char
.
数组的指针
这是C标准中的缺陷。 C 委员会正在做一些工作来解决这个问题。在 draft N2731 中,6.2.5 28 说“……一个数组及其元素类型总是被认为是相同限定的。……”这可以解释指向 char
数组的指针的赋值被分配给指向 char
的 const
限定数组的指针,这是允许的。
与此同时,当您使用 -pedantic
开关时,GCC 是迂腐的。一种补救措施是不要要求它迂腐。另一种是使用显式强制转换。另一种是使用 Clang 或其他编译器。
我有以下两个相似的代码 片段 1:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define W 5
#define N 9
void print_w(const char x[W] [N+1]);
int main()
{
char words[W][N + 1]={{}};
print_w(words);
printf("R*E*V*E*R*E*S*E\n");
print_w( (const char (*) [N+1]) words);
return 0;
}
void print_w(const char x[W] [N+1]){
int i;
for (i=0; i<W; i++) {
printf("Word (%d) :%s\n", i, x[i]);
}
return;
}
片段 2:
#include <stdio.h>
#include <stdlib.h>
#define N 9
void printString(const char []);
int main(){
char mystr[N + 1];
scanf("%9s", mystr);
printString(mystr);
printString( (const char (*) ) mystr);
return 0;
}
void printString(const char str[]){
int i;
for (i=0; str[i]!=0; i++) {
printf("%c\n", str[i]);
}
}
在片段 1 中,我收到一条警告,告诉我在行 print_w(words);
:
[Warning] passing argument 1 of 'print_w' from incompatible pointer type
暗示我必须在 print_w( (const char (*) [N+1]) words);
虽然在代码片段 2 中,我的代码并非如此,因为我在没有警告的情况下执行了这两个选项。
为什么第一个示例中有警告,而第二个示例中没有?我想在函数中传递错误的变量类型 (char --> const) 并非如此,因为在片段 2 中也会出现警告。
这是C标准的缺陷;指向 char
数组的指针与指向 const char
数组的指针不兼容,并且可能无法(通过定义的行为)作为指向 const char
.
注意,数组自动转换后,print_w(words)
传递的是数组指针给print_w
,不是数组的数组,而且,数组参数自动调整后,void print_w(const char x[W] [N+1])
声明 printString
具有指向数组的指针类型的参数,而不是数组的数组。所以我们关心的是数组指针的规则。
对于char (*)[N+1]
和const char (*)[N+1]
,我们首先考虑这些指针类型是否兼容。根据 C 2018 6.7.6.1 2,要使两个指针类型兼容,它们必须指向兼容的类型。
它们指向数组,所以我们看 6.7.6.2 6,它说,要使两种数组类型兼容,两者都应具有兼容的元素类型。
对于元素,我们看 6.7.3 11,它说,对于要兼容的两个限定类型,两者都应具有兼容类型的相同限定版本。 char
和const char
不是全等限定,所以不兼容,所以数组类型不兼容,所以指针类型不兼容。
如果允许对参数类型进行赋值,则函数调用允许传递参数的实参,根据 C 6.5.2.2 2。根据 6.5.16.1 1,赋值允许向 pointed-to 类型“添加”限定符.例如,指向 char
的指针可以分配给指向 const char
的指针。这就是 void printString(const char [])
代码不产生错误或警告消息的原因。但是,规则不允许在类型中更深地添加限定符。因此,指向 char
数组的指针不能分配给指向 const char
.
这是C标准中的缺陷。 C 委员会正在做一些工作来解决这个问题。在 draft N2731 中,6.2.5 28 说“……一个数组及其元素类型总是被认为是相同限定的。……”这可以解释指向 char
数组的指针的赋值被分配给指向 char
的 const
限定数组的指针,这是允许的。
与此同时,当您使用 -pedantic
开关时,GCC 是迂腐的。一种补救措施是不要要求它迂腐。另一种是使用显式强制转换。另一种是使用 Clang 或其他编译器。