C++
在 C++ 2011 (ISO/IEC 14882:2011) 中,相关部分似乎是:
§5.2.2 函数调用[expr.call]
¶6 一个函数可以被声明为接受更少的参数(通过声明默认参数(8.3.6))或更多
参数(通过使用省略号、... 或函数参数包 (8.3.5))比参数的数量
在函数定义(8.4)中。 [注意:这意味着,除了省略号 (...) 或函数
使用参数包,每个参数都有一个参数。 ——尾注]
¶7 当给定参数没有参数时,参数的传递方式使得接收方
函数可以通过调用 va_arg (18.10) 来获取参数的值。 [注:本段不
适用于传递给函数参数包的参数。函数参数包在
模板实例化(14.5.3),因此每个这样的参数在函数时都有一个对应的参数
实际上调用了模板特化。 —尾注] 左值到右值 (4.1)、数组到指针 (4.2) 和
函数到指针 (4.3) 标准转换是在参数表达式上执行的。一个论点
具有(可能是 cv 限定的)类型 std::nullptr_t 被转换为类型 void* (4.10)。在这些转换之后,
如果参数没有算术、枚举、指针、指向成员的指针或类类型,则
程序格式不正确。传递具有非平凡的类类型(第 9 条)的潜在评估参数
复制构造函数、非平凡的移动构造函数或非平凡的析构函数,没有对应的
参数,有条件地支持实现定义的语义。
如果参数有整数
或受积分提升 (4.5) 约束的枚举类型,或受约束的浮点类型
到浮点提升(4.6),参数的值被转换为提升类型之前
通话。这些提升称为默认参数提升。
我将最后两个句子分开以强调它们。它们是标准第 7 段的连续部分。
§4.5 整体促销 [conv.prom]
¶1 整数类型的纯右值,而不是 bool、char16_t、char32_t 或 wchar_t,其整数转换
rank (4.13) 小于int 的rank 可以转换为int 类型的prvalue 如果int 可以代表所有
源类型的值;否则,源纯右值可以转换为unsigned
int 类型的纯右值。
¶2 char16_t、char32_t 或 wchar_t (3.9.1) 类型的纯右值可以转换为第一个纯右值
以下类型可以表示其基础类型的所有值:int、unsigned int、long int、
unsigned long int、long long int 或 unsigned long long int。如果该列表中的任何类型都不能
表示其底层类型的所有值,char16_t、char32_t 或 wchar_t 类型的纯右值可以是
转换为其基础类型的纯右值。
等等
C
C 有两个默认提升参数的上下文。一种是函数范围内没有原型(首先由另一个答案覆盖),第二种是有省略号的原型。当然,C++ 根本不允许第一种情况。这些引用来自另一个答案选择的标准的相同部分,但这里的 sn-ps 有点长。它们是通过独立分析标准发现的,只是在交叉检查时才发现这些部分是相同的。
在 C 2011 (ISO/IEC 9899:2011) 中,相关部分似乎是:
§6.5.2.2 函数调用
¶6 如果表示被调用函数的表达式的类型不包含
原型,整数提升对每个参数执行,参数
具有 float 类型的提升为 double。这些被称为默认参数
促销。如果参数的数量不等于参数的数量,则
行为未定义。如果函数是使用包含原型的类型定义的,并且
原型以省略号 (, ...) 或后面的参数类型结尾
提升与参数的类型不兼容,行为未定义。
如果函数是用不包含原型的类型定义的,那么
提升后的参数与之后的参数不兼容
促销,行为未定义,但以下情况除外:
——一个提升类型是有符号整数类型,另一个提升类型是
对应的无符号整数类型,并且值在两种类型中都可以表示;
——这两种类型都是指向字符类型的合格或不合格版本的指针,或者
无效。
¶7 如果表示被调用函数的表达式具有包含原型的类型,
参数被隐式转换,就像通过赋值一样,转换为
对应的参数,取每个参数的类型为不合格版本
其声明的类型。函数原型声明器中的省略号表示
参数类型转换在最后一个声明的参数之后停止。默认参数
提升是在尾随参数上执行的。
“整数促销”在 §6.3.1.1 中定义:
§6.3.1 算术操作数
§6.3.1.1 布尔值、字符和整数
¶1 每个整数类型都有一个整数转换等级,定义如下:
——没有两个有符号整数类型具有相同的等级,即使它们具有相同的等级
表示。
——有符号整数类型的秩应大于任何有符号整数的秩
输入精度较低。
——long long int 的秩应大于 long int 的秩,即
应该大于int的rank,int的rank应该大于short的rank
int,应大于signed char的等级。
——任何无符号整数类型的等级应等于相应的等级
有符号整数类型,如果有的话。
——任何标准整数类型的秩应大于任何扩展的秩
等宽的整数类型。
——char的秩应该等于signed char和unsigned char的秩。
——_Bool 的等级应小于所有其他标准整数类型的等级。
——任何枚举类型的秩应等于兼容整数类型的秩
(见 6.7.2.2)。
——任何扩展有符号整数类型相对于另一个扩展有符号整数类型的等级
具有相同精度的整数类型是实现定义的,但仍受制于
确定整数转换等级的其他规则。
- 对于所有整数类型 T1、T2 和 T3,如果 T1 的秩大于 T2 且 T2 具有
排名大于 T3,则 T1 排名大于 T3。
¶2 以下内容可用于int 或unsigned int 可能出现的表达式中
使用:
- 具有整数类型的对象或表达式(int 或 unsigned int 除外)
其整数转换等级小于或等于int 的等级并且
unsigned int.
——_Bool、int、signed int 或 unsigned int 类型的位字段。
如果int 可以表示原始类型的所有值(受宽度限制,对于
位域),该值被转换为int;否则,它将转换为unsigned
int。这些被称为整数提升。58)
整数促销。
58) 整数提升仅适用于:作为通常算术转换的一部分,对某些
参数表达式,一元 +、- 和 ~ 运算符的操作数,以及
移位运算符,由它们各自的子条款指定。
我注意到有一次,问题列出了函数void f(...);,这是一个C++函数而不是C函数; C 不允许省略号作为函数的唯一参数出现。该问题已更新为void f(int, ...);,在 C 和 C++ 中均有效。