问题描述
我收到一些关于此代码的奇怪警告:
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
承诺不修改任何 char
的 cpp
可能会被分配一个指向指向非限定 char 的对象的指针,这似乎是合理的
s.毕竟,这允许单个间接指针,这就是为什么,例如,您可以将可变对象传递给 strcpy(3)
的第二个参数,strchr(3) 的第一个参数)
,以及许多其他用 const
声明的参数.
It might seem reasonable that cpp
, which promises not to modify any char
s, might be assigned a pointer to an object pointing at non-qualified char
s. 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.
- Gcc 错误列表:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20230.
- C 常见问题解答:问题 11.10:http://c-faq.com/ansi/constmismatch.html
教训:当需要const T *x
时,你可以传递一个T *x
,通过显式异常,但是T *x
和 const 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 多维数组参数中的奇怪警告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!