【问题标题】:Argument conversion: (normal) pointer to void pointer, cast needed?参数转换:(正常)指向 void 指针的指针,需要强制转换吗?
【发布时间】:2013-12-24 11:03:09
【问题描述】:

当分配给void-指针或从其分配时,不需要强制转换(C99 §6.3.2.2 sub 1 / §6.5.16.1 sub 1)。将(例如int-)指针传递给需要void-指针的函数时,这是否也是如此?

例如:

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

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

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

in this answer 相比,建议此调用需要强制转换(以消除-Wformat 警告):

int main(){
    int i = 12;
    printf("%p\n", &i);
}

但就我而言,GCC 不会抱怨。

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

【问题讨论】:

    标签: c pointers argument-passing


    【解决方案1】:

    区别在于printf 是可变参数函数,可变参数函数在其尾随参数上遵循不同的转换规则。

    foo(&i); 
    

    这里不需要强制转换,因为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) "函数原型声明器中的省略号会导致参数类型转换在最后一个声明的参数之后停止。默认参数提升在尾随上执行 论据。”

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

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

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

    【讨论】:

    • 您似乎在“C 原型函数”和“.. variadic ..”中都引用了同一句话,我假设您的意思是第 7 段的第二部分? “省略号..”
    • 您在调用可变参数函数的相关部分之前停止引用:“函数原型声明器中的省略号表示法会导致参数类型转换在最后一个声明的参数之后停止。默认参数提升在尾随执行论据”。并且提升只对整数类型和浮点数执行,而不是指针。
    • 是的,我错误地粘贴了两次相同的段落,因为我不得不离开。现在,我走了,回来时会解决它。或者如果有人想修正我的答案,欢迎他:)
    • 尾随参数是什么意思?
    • @hacks 尾随参数是与省略号表示法相关的参数(printf 原型中的 ...)。
    猜你喜欢
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 2018-03-05
    • 1970-01-01
    • 1970-01-01
    • 2011-07-31
    • 1970-01-01
    相关资源
    最近更新 更多