C:在函数调用上传递参数时的类型转换

Mid*_*lue 15 c type-conversion

来自C编程语言第2版:

由于函数调用的参数是表达式,因此在将参数传递给函数时也会发生类型转换.在没有函数原型的情况下,char和short变为int,float变为double.

通过阅读文本,我得到的印象是,除非您通过使用强制转换或函数原型显式指定参数类型,否则函数参数将始终作为int或double传递.

为了验证我的假设,我编译了以下代码:

#include <stdio.h>

main()
{
     unsigned char c = 'Z';
     float number = 3.14f;
     function_call(c, number);
}

void function_call(char c, float f)
{
}
Run Code Online (Sandbox Code Playgroud)

编译后我得到以下警告:

typeconversion.c:11:警告:'function_call'的冲突类型

typeconversion.c:7:警告:'function_call'之前的隐式声明就在这里

我的猜测是c和数字都在函数调用中转换为int和double,然后转换回char和float.这是真的发生了什么?

Mic*_*man 19

演员阵容无关紧要,重要的是(可能隐含的)原型.

void foo(short s) {
    // do something
}

int main(void) {
  signed char c = 'a';

  foo(c);  // c is promoted to short by explicit prototype
  bar(c);  // c is promoted to int by implicit prototype
}

void bar(int i) {
    // do something
}
Run Code Online (Sandbox Code Playgroud)

当书中写着"函数调用的参数是表达式"时,它意味着适用相同类型的促销规则.如果将函数参数视为对函数原型中指定的变量的隐式赋值,则可能更容易理解.例如,在foo()上面的调用中有一个隐含的short s = c.

这就是演员无关紧要的原因.请考虑以下代码段:

signed char c = 'a';
int i = (short) c;
Run Code Online (Sandbox Code Playgroud)

这里c的值首先被提升为short(显式地)然后被提升为int(隐式地).价值i总是一个int.

至于charshort成为intfloat变成double,指的是隐式函数原型的默认类型.当编译器在看到函数的原型或函数定义之前看到对函数的调用时,它会自动生成原型.它默认int为整数值和double浮点值.

如果最终的函数声明与隐式原型不匹配,您将收到警告.


Tyl*_*nry 16

你已经大致了解了什么是错的,但并不完全正确.

你写的时候发生了什么事

function_call(c, number);
Run Code Online (Sandbox Code Playgroud)

编译器看到你正在调用一个它尚未见过的函数,因此必须决定它的签名应该是什么.根据您之前引用的促销规则,它将char提升为int并将float提升为double并确定签名为

function_call(int, double)
Run Code Online (Sandbox Code Playgroud)

然后当它看到

function_call(char c, float f)
Run Code Online (Sandbox Code Playgroud)

它将此解释为具有相同名称的不同函数的签名,这在C中是不允许的.它与您实际定义函数的原型不同的错误完全相同,只是在这种情况下原型是隐式的由编译器生成.

因此,正是这个规则引起了问题,但错误与实际在类型之间来回转换值没有任何关系.