C语言的自动参数提升(default argument promotion)规则

我在网上翻了一下,不太满意。

有没有人能讲清楚:
1.   除了在va_arg()中提取参数时可能用到外,这个default   argument   promotion规则什么时候会被用到?
2.   这个问题的来源是什么?为什么需要这条规则?
3.   它的精确定义到底是什么?

4.   在这问题上K&R   C和ANSI   C有没有区别?是什么区别


主要的几个地方:
1、可变参数列表,即va_arg(),这个是规定,因为编译器不知道函数原型,更不知道你的函数内部要的是什么类型,所以定义了这个规则。
2、算术运算,这个是小的应用
3、函数参数匹配,比如声明了void   f(double),你调用f(1)是可以的,就是这个规则在起作用;f( "hello ")不行,也是这个规则。
4、进一步的,函数参数匹配也用在C++的函数overloading里,这时就可能会引起二义性。



我觉得你说的算术运算和第3点中的f(1)和这个va_arg()中遇到的default   argument   promotion规则还是有不同之处的。

算术运算以及调用f(1)时我认为不能算是一个default   argument   promotion,   常量的类型是在编译时根据函数原型指定好了的,这里并没有发生提升的情况。(仅仅是完成一次语义上的转化,一般的编译原理书上都有讲)

而用va_arg(arg,   type)提取参数时,va_arg()事先并不知道以什么类型提取(因为是以变参中的...表示的),所以在这种情况下,比如在格式中遇到一个%c,它仍然是以va_arg(arg,   int)方式来提取这个char类型的参数,而这种情况和上面的f(1)我觉得是有区别的。这里的区别问题在于,变参中的参数...是不是**总是**以提升后的类型压栈的?比如说,考虑下面这个函数:

void   PrintMsg(char   *errMsg   ,   ...);

对这个函数有以下的调用:
PrintMsg( "%c   %d   %f\n ",   1,   2,   3);

这里的三个参数3,2,1在调用者压栈时分别是以什么类型压进去的呢?是不是参数1和2都是以int方式压栈,而3用double方式压栈?我认为编译器无法解决这个问题,它如何知道3在压栈时应该使用double类型呢?而同样的,如果不能确定栈上的参数类型,va_arg()在运行时又如何知道应该用float/double类型提取3这个参数呢?


PrintMsg( "%c   %d   %f\n ",   1,   2,   3);
的确全是以int(4字节)压栈的。而对于:

PrintMsg( "%c   %d   %f\n ",   a,   b,   c);
其中a,   b,   c分别为char,   int   float类型的参数,
a和b分别以4字节压栈,   c以float压栈(8字节)。

试验环境为32bit   x86,   FreeBSD/gcc2.95.3


va_arg()这个宏在处理变参...的时候,对于所有char,   short类型的参数
都以int类型提取,对于float类型的参数都以double类型提取。


C语言允许不知道函数原型的情况下调用函数,所以,为了避免出现参数类型不一致引起的问题,在函数调用时,要进行type promotion,如short、int提升为int,float提升为double等。
这样,在进入函数时,要将promote后参数根据其类型进行处理。如果参数类型就是int、void*等不需要promote的类型,则其在栈里的位置不变。


你可能感兴趣的:(C语言的自动参数提升(default argument promotion)规则)