本文介绍了C 函数 const 多维数组参数中的奇怪警告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm getting some strange warnings about this code:

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)
{
}

或者在 main 中定义矩阵为:

Or defining matrices in main as:

mat4 mr;
const mat4 ma;
const mat4 mb;

或者调用 main 中的函数为:

Or call the function in main as:

mprod4(mr, (const double(*)[4])ma, (const double(*)[4])mb);

甚至定义 mat4 为:

typedef double mat4[16];

使警告消失.这里发生了什么?我在做一些无效的事情吗?

Makes the warning go away. What is happening here? Am I doing something invalid?

gcc 版本为 4.4.3(如果相关).

The gcc version is 4.4.3, if relevant.

我还在 gcc bugzilla 上发帖:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47143

I also posted on gcc bugzilla: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47143

我目前的解决方法是制作丑陋的宏来为我投射内容:

My current workaround is making ugly macros that cast stuff for me:

#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 的回答:


Answer from Joseph S. Myers on gcc bugzilla:

不是错误.函数参数类型为指向数组[4]的指针const double" 因为 const 在数组类型适用于元素递归地键入,然后仅最外层数组类型数组类型的参数衰减为指针,传递的参数是类型指向数组[4]的指针double" 数组到指针衰减后,并且限定符是唯一的情况允许在赋值中添加,参数传递等是限定符直接指针目标,而不是那些嵌套更深的.

听起来对我来说很混乱,就像函数所期望的那样:

Sounds pretty confusing to me, like the function expects:

pointer to array[4] of const doubles

我们正在路过

pointer to const array[4] of doubles

相反.

或者相反?警告表明该函数需要一个:

Or would it be the inverse? The warnings suggest that the function expects a:

const double (*)[4]

在我看来更像是一个

pointer to const array[4] of doubles

我真的对这个答案感到困惑.能听懂他的话的人解释一下吗?

I'm really confused with this answer. Could somebody who understands what he said clarify and exemplify?

推荐答案

我认为问题出在 C99 6.5.16.1(1) 中指定的约束,这似乎禁止在赋值中混合限定,但定义了包含限定符异常的指针除外.问题是,使用间接指针,您最终会将指向一件事的指针传递给指向另一件事的指针.赋值无效,因为如果它是,你可以欺骗它使用以下代码修改一个 const 限定的对象:

I believe the problem is the constraints specified in C99 6.5.16.1(1), which seem to prohibit mixing qualifications in assignments, except for pointers for which an inclusive-qualifier exception is defined. The problem is that with indirect pointers, you end up passing a pointer to one thing to a pointer to another. The assignment isn't valid because, if it was, you could fool it into modifying a const-qualified object with the following code:

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

承诺不修改任何 charcpp 可能会被分配一个指向指向非限定 char 的对象的指针,这似乎是合理的 s.毕竟,这允许单个间接指针,这就是为什么,例如,您可以将可变对象传递给 strcpy(3) 的第二个参数,strchr(3) 的第一个参数),以及许多其他用 const 声明的参数.

It might seem reasonable that cpp, which promises not to modify any chars, might be assigned a pointer to an object pointing at non-qualified chars. After all, that's allowed for single-indirect pointers, which is why, e.g., you can pass a mutable object to the second parameter of strcpy(3), the first parameter to strchr(3), and many other parameters that are declared with const.

但是对于间接指针,在下一级,允许从限定指针进行赋值,现在完全不限定指针赋值会破坏限定对象.

But with the indirect pointer, at the next level, assignment from a qualified pointer is allowed, and now a perfectly unqualified pointer assignment will clobber a qualified object.

我没有立即看到二维数组如何导致这种情况,但无论如何它都会遇到标准中的相同约束.

I don't immediately see how a 2-D array could lead to this situation, but in any case it hits the same constraint in the standard.

因为在您的情况下,您实际上并没有欺骗它来破坏常量,所以对于您的代码来说,正确的做法似乎是插入演员表.

Since in your case, you aren't actually tricking it into clobbering a const, the right thing for your code would seem to be inserting the cast.

更新:好的伙计们,碰巧这个问题是在 C 常见问题解答中,整个讨论也发生了多次在 gcc 错误列表 和 gcc 邮件列表上.

Update: OK guys, as it happens this issue is in the C faq, and this entire discussion has also taken place several times on the gcc bug list and on the gcc mailing list.

教训:当需要const T *x时,你可以传递一个T *x,通过显式异常,但是T *xconst T *x 仍然是不同的类型,所以你不能将一个指针传递给另一个.

The lesson: you can pass a T *x when const T *x is expected, by explicit exception, but T *x and const T *x are still distinct types, so you can't pass a pointer to either one to a pointer to the other.

这篇关于C 函数 const 多维数组参数中的奇怪警告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-23 07:53
查看更多