将具有 const 参数的函数分配给具有非 const 参数的函数指针

Assign function with const argument to function pointer with non const argument

注:我看过。虽然它适用于 C++,但已接受的答案似乎暗示这不应该成为问题。

我用 gccg++ 都编译过,但有同样的问题。 (g++ 给出错误,gcc 给出警告,但我认为这是由于不同的默认标志造成的)。

我们在工作中使用的某个静态分析/linter 工具(应保持匿名)导致此问题。由于函数不修改指针 int* num 或数据本身,我 应该 (必须)将函数参数声明为 const int* const num.

    typedef int (*funcptr)(int* num);
    
    int func1(      int* num)      { return *num +1; }
    int func2(const int* num)      { return *num +1; }
    int func3(      int* const num){ return *num +1; }
    int func4(const int* const num){ return *num +1; }
    
    int main(const int argc, const char** const argv){
        funcptr fptr;
        fptr = func1; //No warning - Signature exactly matches funcptr
        fptr = func2; //WARNING
        fptr = func3; //No warning
        fptr = func4; //WARNING
    }

gcc minimal.c

minimal.c:13:10: warning: assignment to ‘funcptr’ {aka ‘int (*)(int *)’} from incompatible pointer type ‘int (*)(const int *)’ [-Wincompatible-pointer-types]
   13 |     fptr = func2;
      |          ^
minimal.c:15:10: warning: assignment to ‘funcptr’ {aka ‘int (*)(int *)’} from incompatible pointer type ‘int (*)(const int * const)’ [-Wincompatible-pointer-types]
   15 |     fptr = func4;

g++ minimal.c

minimal.c: In function ‘int main(int, const char**)’:
minimal.c:13:12: error: invalid conversion from ‘int (*)(const int*)’ 
to ‘funcptr’ {aka ‘int (*)(int*)’} [-fpermissive]
   13 |     fptr = func2;
      |            ^~~~~
      |            |
      |            int (*)(const int*)
minimal.c:15:12: error: invalid conversion from ‘int (*)(const int*)’ 
to ‘funcptr’ {aka ‘int (*)(int*)’} [-fpermissive]
   15 |     fptr = func4;
      |            ^~~~~
      |            |
      |            int (*)(const int*)

编辑: 由于接受了答案,我明白为什么该标准适用于上述代码。但为什么以下内容可以接受?

gcc minimal.c -Wall -Werror

int func(const int* const num){ return *num +1; }

int main(const int argc, const char** const argv){
    int aNumber = 4;
    int ret = func(&aNumber);
    return ret;
}

函数指针 funcptr 实际上与 func2 不兼容。

两个函数类型兼容(忽略 ... 或 old-style 参数声明的情况)如果它们的 return 类型兼容,则它们具有相同数量的参数,并且参数类型兼容。前两种情况显然是满意的,所以有趣的部分是第三种情况。

当涉及类型限定符时,如果两种类型是兼容类型的相同限定版本,则它们是兼容的。根据这个定义, const int *int * 兼容。因此,funcptrfunc2 不兼容。

虽然指向 non-qualified 类型的指针可以转换为指向相同类型的合格版本的指针,但根据上述规则,这不适用于函数参数。

兼容限定类型的规则在 C standard 的第 6.7.3p10 节中有详细说明:

For two qualified types to be compatible, both shall have the identically qualified version of a compatible type; the order of type qualifiers within a list of specifiers or qualifiers does not affect the specified type.

兼容函数类型的规则在第 6.7.6.3p15 节中列出:

For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions. If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list, both shall agree in the number of parameters, and the type of each prototype parameter shall be compatible with the type that results from the application of the default argument promotions to the type of the corresponding identifier. (In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.)

末尾括号内的部分需要特别注意。它基本上是说,如果参数是 const,则为了确定兼容性而将其省略。这就是 func3 不会触发警告的原因,因为类型 int * const 的参数在此上下文中等同于 int *.

适用于func2,因为参数指向的是const,而不是参数本身。所以const int *类型的参数是而不是调整为int *.