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

out4b 2003-08-04 05:47:47
我在网上翻了一下,不太满意。

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


谢谢。
...全文
290 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
out4b 2003-08-05
  • 打赏
  • 举报
回复
补充:刚才试了一下,对于:

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



Riversking(纸风筝) :

可否详细讲讲?
fierygnu 2003-08-05
  • 打赏
  • 举报
回复
1、是我写例子时懒了一下,写成f(int(1))就是了。这是我的本意。
2、变参中的参数...是**总是**以提升后的类型压栈的。你的PrintMsg("%c %d %f\n", 1, 2, 3);调用会出问题,PrintMsg("%c %d %f\n", 1, 2, 3.0);就不会出问题了。这个不是编译器的职责,是程序员的职责。这就是使用可变参数列表的危险所在。
3、va_arg()在运行时是根据你编程时指定的类型提取3这个参数的。
Riversking 2003-08-05
  • 打赏
  • 举报
回复
c程序设计有详细说明。清华的。谭老写的。
out4b 2003-08-05
  • 打赏
  • 举报
回复
fierygnu(va_list):

我觉得你说的算术运算和第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这个参数呢?
fierygnu 2003-08-05
  • 打赏
  • 举报
回复
主要的几个地方:
1、可变参数列表,即va_arg(),这个是规定,因为编译器不知道函数原型,更不知道你的函数内部要的是什么类型,所以定义了这个规则。
2、算术运算,这个是小的应用
3、函数参数匹配,比如声明了void f(double),你调用f(1)是可以的,就是这个规则在起作用;f("hello")不行,也是这个规则。
4、进一步的,函数参数匹配也用在C++的函数overloading里,这时就可能会引起二义性。
out4b 2003-08-05
  • 打赏
  • 举报
回复
Caoyu015(Cooyu(酷鱼一代)) :

算术运算时的自动类型提升肯定会发生的,你还提到一种情况是形参和实参转换时的自动提升是指什么呢?

我的问题是从va_arg()来的,这个宏在处理变参...的时候,对于所有char, short类型的参数
都以int类型提取,对于float类型的参数都以double类型提取。我不太清楚的是,这样做的依据何在?
out4b 2003-08-05
  • 打赏
  • 举报
回复
说实在的我还是有点迷惑,不过就这样吧,先把分给了再说。:)
fierygnu 2003-08-05
  • 打赏
  • 举报
回复
1、我用了C++的方式。
3、这样理解也行。
out4b 2003-08-05
  • 打赏
  • 举报
回复
fierygnu(va_list) :

1. 应该是f((int)1)吧?
2. sorry我写错了,编译器肯定知道3和3.0的区别。:)
3. 我是不是可以说,这个自动提升规则是不是*仅仅*在不清楚参数类型的情况(如变参)才会发生?
ckacka 2003-08-04
  • 打赏
  • 举报
回复
double的精度比float高
magic007 2003-08-04
  • 打赏
  • 举报
回复
C语言没仔细研究过,不过C++ 在c++ primer上讲得很清楚
Caoyu015 2003-08-04
  • 打赏
  • 举报
回复
很久没有温习以前的C语言基础部分了,如果有错误请见晾。:)
Caoyu015 2003-08-04
  • 打赏
  • 举报
回复
基本类型: char-> short-> int-> long-> double-> float .
在两个不同类型之间发生算术运算 如:

char ch = 'a';
float fs = 9.88;

fs = ch + fs; //运算时是直接的提升到float类型,而不是先提升到 short ->int -> long;
再到 float;
这种例子有很多。

out4b 2003-08-04
  • 打赏
  • 举报
回复
能否说详细一点?
Caoyu015 2003-08-04
  • 打赏
  • 举报
回复
参数提升一般发生在从实参到形参的转换和一般的算术运算之时。
提升的规则应该在教课书的前几页上就有。
out4b 2003-08-04
  • 打赏
  • 举报
回复
关注一下,不要跑到第二页去了。:)

69,372

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧