问题描述
typedef double mat4 [4] [4];
void mprod4(mat4 r,const mat4 a,const mat4 b)
{
/ * yes,函数为空* /
}
int main()
{
mat4 mr,ma,mb;
mprod4(mr,ma,mb);
}
gcc
输出为如下所示:
$ $ $ $ gcc -o test test.c
test.c:在函数'main'中:
test.c:13:warning:从不兼容指针传递'mprod4'的参数2
类型
test.c:4:注意:期望'const double(*)[4]'但参数是'double
(*)[4]'
test.c:13:warning:从不兼容的指针传递'mprod4'的参数3
类型
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;
或者在main中调用该函数:
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上的答案:
听起来很让人困惑,就像函数期望的那样: p>
指向数组[4]的const double的
并且我们正在传递
指向double数组$ [
。
或者它会是逆?警告提示该函数需要一个:
pre $ const double(*)[4]
这在我看来更像是一个
指向常量数组[4]的双打
我对这个答案感到困惑。是否有人理解他所说的澄清和举例?
我相信问题是在 C99 6.5.16.1(1),它似乎禁止赋值中的混合限定,除了定义了包含限定符异常的指针外。问题在于,对于间接指针,您最终会将指向某个指针的指针传递给另一个指针。这个赋值是无效的,因为如果是这样的话,你可以用它来修改一个const限定的对象:
const char ** cpp;
char * p;
const char c ='A';
cpp =& p; //违反约束条件
* cpp =& c; //有效
* p = 0; //本身有效,但会破坏c
看起来合理的是 cpp
,它承诺不会修改任何 char
s,可能会分配一个指向指向非限定炭
秒。毕竟,这允许使用单一间接指针,这就是为什么,例如,您可以将可变对象传递给第二个参数 strcpy(3)
,这是第一个参数 strchr(3)
,以及许多用 const
声明的参数。
但是对于间接指针,在下一级,允许从限定指针进行赋值,现在完全不合格的指针赋值将会打断合格对象。
我不会立即看到二维数组如何导致这种情况,但无论如何它在标准中遇到相同的约束。
因为在你的情况下,你实际上并没有把它变成clobbering一个const,你的代码的正确的东西似乎是插入
更新:好吧,碰巧这个问题是 ,而且整个讨论也发生过几次 和关于gcc邮件列表。
- 海湾合作委员会错误清单: 。
- C FAQ:问题11.10:
课程:您可以传递 T * x
>当通过显式异常,但是
仍然是不同的类型,所以你不能将一个指针传递给另一个指向另一个指针。 T * x
和<$时,期望 const T * x
c $ c> const T * x
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
output as follows:
$ 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]'
If I define the function as:
void mprod4(mat4 r, mat4 a, mat4 b)
{
}
Or defining matrices in main as:
mat4 mr;
const mat4 ma;
const mat4 mb;
Or call the function in main as:
mprod4(mr, (const double(*)[4])ma, (const double(*)[4])mb);
Or even defining mat4
as:
typedef double mat4[16];
Makes the warning go away. What is happening here? Am I doing something invalid?
The gcc version is 4.4.3, if relevant.
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
Answer from Joseph S. Myers on gcc bugzilla:
Sounds pretty confusing to me, like the function expects:
pointer to array[4] of const doubles
and we are passing
pointer to const array[4] of doubles
intead.
Or would it be the inverse? The warnings suggest that the function expects a:
const double (*)[4]
which seems to me more like a
pointer to const array[4] of doubles
I'm really confused with this answer. Could somebody who understands what he said clarify and exemplify?
解决方案 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
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.
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 bug list: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20230.
- C FAQ: it's question 11.10: http://c-faq.com/ansi/constmismatch.html
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多维数组参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!