Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C函数常量多维数组参数中的奇怪警告_C_Function_Multidimensional Array_Constants_Arguments - Fatal编程技术网

C函数常量多维数组参数中的奇怪警告

C函数常量多维数组参数中的奇怪警告,c,function,multidimensional-array,constants,arguments,C,Function,Multidimensional Array,Constants,Arguments,我收到一些关于此代码的奇怪警告: typedef double mat4[4][4]; void mprod4(mat4 r, const mat4 a, const mat4 b) { /* yes, function is empty */ } int main() { mat4 mr, ma, mb; mprod4(mr, ma, mb); } gcc输出如下: $ gcc -o test test.c test.c: In function 'main': test

我收到一些关于此代码的奇怪警告:

typedef double mat4[4][4];

void mprod4(mat4 r, const mat4 a, const mat4 b)
{
/* yes, function is empty */
}

int main()
{
    mat4 mr, ma, mb;
    mprod4(mr, ma, mb);
}
gcc
输出如下:

$ gcc -o test test.c
test.c: In function 'main':
test.c:13: warning: passing argument 2 of 'mprod4' from incompatible pointer
type
test.c:4: note: expected 'const double (*)[4]' but argument is of type 'double
(*)[4]'
test.c:13: warning: passing argument 3 of 'mprod4' from incompatible pointer
type
test.c:4:
note: expected 'const double (*)[4]' but argument is of type 'double
(*)[4]'
如果我将函数定义为:

void mprod4(mat4 r, mat4 a, mat4 b)
{
}
或主要将矩阵定义为:

mat4 mr;
const mat4 ma;
const mat4 mb;
mprod4(mr, (const double(*)[4])ma, (const double(*)[4])mb);
或调用main中的函数,如下所示:

mat4 mr;
const mat4 ma;
const mat4 mb;
mprod4(mr, (const double(*)[4])ma, (const double(*)[4])mb);
甚至将
mat4
定义为:

typedef double mat4[16];
使警告消失。这里发生了什么?我在做一些无效的事情吗

如果相关,gcc版本为4.4.3

我还在gcc bugzilla上发布了:

我目前的解决方法是制作难看的宏,为我投射东西:

#ifndef _NO_UGLY_MATRIX_MACROS

#define mprod4(r, a, b) mprod4(r, (const double(*)[4])a, (const double(*)[4])b)

#endif

Joseph S.Myers关于gcc bugzilla的回答:

不是虫子。函数参数 类型为“指向数组[4]的指针” 常数加倍“因为常数在 数组类型应用于元素 输入,递归地,然后输入 仅限阵列的最外层数组类型 数组类型的参数衰减为 指针,并且传递的参数为 类型为“指向数组[4]的指针” 数组到指针衰减后的“double”, 而且限定符是 允许在转让中添加, 参数传递等是限定符 直接指针目标,而不是 那些嵌套得更深

听起来我很困惑,就像函数期望的那样:

pointer to array[4] of const doubles
我们正在经过

pointer to const array[4] of doubles
国际贸易署

还是相反?警告表明该函数需要:

const double (*)[4]
在我看来,这更像是一个

pointer to const array[4] of doubles

我真的对这个答案感到困惑。理解他所说的话的人能澄清并举例说明吗?

我认为问题在于C996.5.16.1(1)中规定的约束,这似乎禁止在作业中混合限定符,但定义了包含限定符例外的指针除外。问题是,对于间接指针,您最终会将指向一个对象的指针传递给指向另一个对象的指针。该赋值无效,因为如果它是有效的,您可以用以下代码愚弄它修改常量限定对象:

const char **cpp;
char *p;
const char c = 'A';
cpp = &p;  // constraint violation
*cpp = &c; // valid
*p = 0;    // valid by itself, but would clobber c
似乎合理的做法是,向承诺不修改任何
char
s的
cpp
分配指向指向非限定
char
s的对象的指针。毕竟,单间接指针是允许的,这就是为什么,例如,您可以将可变对象传递给
strcpy(3)
的第二个参数,传递给
strchr(3)
的第一个参数,以及使用
常量声明的许多其他参数

但是对于间接指针,在下一个级别,允许从限定指针赋值,而现在完全限定的指针赋值将重击限定对象

我并没有立即看到二维阵列如何导致这种情况,但在任何情况下,它都会遇到标准中的相同约束

因为在你的例子中,你实际上并不是在欺骗它去敲一个常量,你的代码的正确做法似乎是插入强制转换


更新:好的,伙计们,碰巧这个问题是,整个讨论也在gcc邮件列表上进行了多次

  • Gcc错误列表:
  • C常见问题解答:问题11.10:

教训:通过显式异常,当需要
const T*x
时,可以传递
T*x
,但是
T*x
const T*x
仍然是不同的类型,因此不能将指向其中一个的指针传递给指向另一个的指针。

编译器只是在分析

传递的参数本质上是非常量指针,函数声明为接受常量指针作为参数。事实上,这两者是不相容的。这不是一个真正的问题,因为只要您可以将第一种类型的值分配给第二种类型的变量,编译器就仍然可以工作。因此,这是一个警告,而不是一个错误

编辑:看起来gcc不会抱怨其他con-const-to-const转换,例如,在需要const-char*的地方传递char*。在这种情况下,我倾向于同意来自Bugzilla的Joseph Myers是正确的。

这里有一个问题(IMHO):
函数签名中的双[4][4]

您知道它是一个
double[4][4]
,但是编译器在函数参数列表中看到
double(*)[4]
,这显然没有数组大小约束。它将由4×4个对象组成的二维数组转换为指向由4个对象组成的一维数组的指针,指针可以有效地索引,就像它是由4个对象组成的数组一样

我将通过指针传递所有
mat4
对象:

void mprod4(mat4 *r, const mat4 *a, const mat4 *b);
// and, if you don't want to hairy your syntax
#define mprod4(r, a, b) (mprod4)(&r, (const mat4 *)&a, (const mat4 *)&b)
这将(我相信)确保常量正确性和数组大小正确性。它可能会使mprod4的编写变得有点困难,并且仍然会涉及到一些毛茸茸的造型,但它(IMHO)是值得的(尤其是在上面的宏之后):

void mprod4(mat4*r、const mat4*a、const mat4*b)
{
//所有矩阵索引必须在解引用后进行
for(int i=0;i<4;i++)for(int j=0;j<4;j++)
{
(*r)[i][j]=(*a)[i][j]*(*b)[i][j];
//如果您愿意,您可以让自己更轻松:
#定义idx(a,i,j)((*a)[i][j])
idx(r,i,j)=idx(a,i,j)*idx(b,i,j)
}
}

当你写它的时候,它可能看起来有点糟糕,但我认为它会更简洁。(也许我一直在思考C++太多…)

我认为在C99中,你可以做到这一点,但我不确定它会有什么帮助:

void mprod4(double mr[4][4], double ma[const 4][const 4], double mb[const 4][const 4])
{

}
我手头没有C99编译器,但我记得在C99规范中读到了一些关于
[]
中数组作为参数的限定符的内容。您也可以将
static
放入其中(例如
ma[static 4]
),但这当然意味着其他内容

编辑 此处为第6.7.3.5节第7段

将参数声明为“类型数组”应调整为“类型的限定指针”,其中类型限定符(如有)为spe
int x1 = 0;
const int x2 = x1;  // ok
int *x3 = &x1;
const int *x4 = x3;  // ok: convert "pointer to int" to "pointer to const int"
int **x5 = &x3;
const int **x6 = x5;  // ERROR: see DigitalRoss's answer
int *const *x7 = x5;  // ok: convert "pointer to (pointer to int)" to
                      //             "pointer to const (pointer to int)"