参数转换:(正常)指向void指针的指针,需要强制转换吗?

Kni*_*nug 6 c pointers argument-passing

当分配到void-pointer 或从-pointer 分配时,不需要强制转换(C99§6.3.2.2sub 1/§6.5.16.1sub 1).将(例如int- )指针传递给期望void-pointer 的函数时,这也是正确的吗?

例如:

void foo(void * p){
    // Do something
}

int main(){
    int i = 12;
    foo(&i); // int * to void *: no cast needed?
}
Run Code Online (Sandbox Code Playgroud)

当我使用GCC(4.8.1,MinGW-32)编译它时,我既没有错误也没有警告(使用-Wall&-pedantic).

此答案相反,建议此调用需要强制转换(以消除-Wformat警告):

int main(){
    int i = 12;
    printf("%p\n", &i);
}
Run Code Online (Sandbox Code Playgroud)

但就我而言,海湾合作委员会并没有抱怨.

那么:将非void指针传递给期望void-pointer 的函数时需要进行强制转换吗?

oua*_*uah 6

区别在于printf可变参数函数和可变参数函数遵循其尾随参数的不同转换规则.

foo(&i); 
Run Code Online (Sandbox Code Playgroud)

这里不需要强制转换,因为foo它是原型函数.C表示&i将转换为p类似于赋值的类型,而在C中,所有对象指针类型之间都存在隐式void *.

这种情况printf不同,因为可变参数函数printf在其余参数上具有默认参数提升,并且指针类型的参数不会发生转换.

关于原型函数的C:

(C99,6.5.2.2p7)"如果表示被调用函数的表达式具有包含原型的类型,则将参数隐式转换为相应参数的类型,就像通过赋值一样,取每个类型的类型参数是其声明类型的非限定版本."

关于可变函数的C:

(C99,6.5.2.2p7)"(C99,6.5.2.2p7)"函数原型声明符中的省略号表示法导致参数类型转换在最后声明的参数之后停止.默认参数提升是在尾随参数上执行的."

那么:将非void指针传递给需要void指针的函数时需要强制转换吗?

对于printf,p转换说明符需要void *参数.如果参数的类型不同,则函数调用将调用未定义的行为.因此,如果参数p是对象指针类型,(void *)则需要强制转换.

(C99,7.19.6.1p8)"p参数应该是指向void的指针."