char是默认提升的吗?

这可能是个愚蠢的问题,但有人可以为C ++ 11和C11提供标准参考:

char是否默认提升为int

这里有一点背景:C和C ++都有默认参数提升的概念(C ++ 11:5.2.2 / 7; C11:6.5.2.2/6)。 这需要在以下调用中提升参数:

 void f(int, ...); float a = 1; short int b = 2; char c = 'x'; f(0, a, b, c); 

对于函数调用, a转换为doubleb转换为int 。 但是c会发生什么? 我一直认为char也被提升为int ,但我无法在标准中找到相关的陈述。

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),因此当实际调用函数模板特化时,每个这样的参数都具有相应的参数。 -end note]对参数表达式执行左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)标准转换。 具有(可能是cv-qualified)类型std :: nullptr_t的参数将转换为void *(4.10)类型。 在这些转换之后,如果参数没有算术,枚举,指针,成员指针或类类型,则程序格式错误。 通过实现定义的语义有条件地支持传递具有非平凡复制构造函数,非平凡移动构造函数或非平凡析构函数的类类型(第9章)的潜在评估参数,其中没有相应的参数。

如果参数具有受整数提升(4.5)或浮点类型(受浮点提升(4.6)约束)的积分或枚举类型,则参数的值将在调用之前转换为提升类型。 这些促销被称为默认参数促销。

我把最后两个句子分开来强调它们。 它们是标准第7段的连续部分。

§4.5整体促销[conv.prom]

¶1除了boolchar16_tchar32_twchar_t之外的整数类型的prvalue,其整数转换等级(4.13)小于int的等级,如果int可以表示所有的值,则可以转换为int类型的prvalue。来源类型; 否则,源prvalue可以转换为unsigned int类型的prvalue。

¶2char16_t, char32_twchar_t (3.9.1)类型的prvalue可以转换为以下第一种类型的prvalue,它们可以表示其基础类型的所有值: intunsigned intlong intunsigned long intlong long intunsigned long long int 。 如果该列表中的任何类型都不能表示其基础类型的所有值,则可以将char16_tchar32_twchar_t类型的prvalue转换为其基础类型的prvalue。

等等。


C

C有两个上下文,其中参数是默认提升的。 一个是函数范围内没有原型(第一个由另一个答案覆盖),第二个是带有省略号的原型。 当然,C ++根本不允许第一种情况。 这些引用来自另一个答案选择的标准的相同部分,但这里的片段稍长。 他们是通过对标准的独立分析找到的,只有在交叉检查时我才注意到这些部分是相同的。

在C 2011(ISO / IEC 9899:2011)中,相关部分似乎是:

§6.5.2.2函数调用

¶6如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升,并将类型为float的参数提升为double。 这些被称为默认参数促销。 如果参数的数量不等于参数的数量,则行为是未定义的。 如果使用包含原型的类型定义函数,并且原型以省略号( , ... )结尾,或者促销后的参数类型与参数类型不兼容,则行为未定义。 如果使用不包含原型的类型定义函数,并且促销后的参数类型与促销后的参数类型不兼容,则行为未定义,但以下情况除外:

– 一个提升类型是有符号整数类型,另一个提升类型是相应的无符号整数类型,并且该值可在两种类型中表示;

– 两种类型都是指向字符类型或void的限定或非限定版本的指针。

¶7如果表示被调用函数的表达式具有包含原型的类型,则将参数隐式转换为相应参数的类型,就像通过赋值一样,将每个参数的类型作为不合格的版本它的声明类型。 函数原型声明符中的省略号表示法导致参数类型转换在最后声明的参数之后停止。 默认参数提升是在尾随参数上执行的。

‘整数促销’在§6.3.1.1中定义:

§6.3.1算术操作数

§6.3.1.1布尔,字符和整数

¶1每个整数类型都有一个整数转换等级,定义如下:

– 没有两个有符号整数类型具有相同的等级,即使它们具有相同的表示。

– 有符号整数类型的等级应大于精度较低的任何有符号整数类型的等级。

– long long int的等级应大于long int的等级,该等级应大于int的等级,该等级应大于short int的等级,short rank应大于signed char的等级。

– 任何无符号整数类型的等级应等于相应的有符号整数类型的等级(如果有)。

– 任何标准整数类型的等级应大于具有相同宽度的任何扩展整数类型的等级。

– char的等级应等于signed char和unsigned char的等级。

– _Bool的等级应小于所有其他标准整数类型的等级。

– 任何枚举类型的等级应等于兼容整数类型的等级(见6.7.2.2)。

– 任何扩展有符号整数类型相对于另一个具有相同精度的扩展有符号整数类型的等级是实现定义的,但仍然受制于确定整数转换等级的其他规则。

– 对于所有整数类型T1,T2和T3,如果T1的秩大于T2且T2的秩大于T3,则T1的秩大于T3。

¶2可以在任何可以使用intunsigned int的表达式中使用以下内容:

– 具有整数类型( intunsigned int除外)的对象或表达式,其整数转换等级小于或等于intunsigned int的等级。

_Boolintsigned intunsigned int类型的位字段。

如果int可以表示原始类型的所有值(由宽度限制,对于位字段),该值将转换为int ; 否则,它将转换为unsigned int 。 这些被称为整数促销58)所有其他类型由整数促销不变。

58)整数提升仅适用于:通常算术转换的一部分,某些参数表达式,一元+, – 和〜运算符的操作数,以及移位运算符的两个操作数,由它们各自指定小节。


我注意到,有一次,问题列出了函数void f(...); ,这是一个C ++函数而不是C函数; C不允许省略号作为函数的唯一参数出现。 此问题已更新为void f(int, ...); 这在C和C ++中都有效。

首先,默认参数促销

6.5.2.2

如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升 ,并将具有float类型的参数提升为double。 这些被称为默认参数促销

现在进行整数促销:

6.3.1.1

如果可以使用int或unsigned int,则可以在表达式中使用以下内容:

  • 具有整数类型(int或unsigned int除外)的对象或表达式,其整数转换等级小于或等于int和unsigned int的等级。

如果int可以表示原始类型的所有值(由宽度限制,对于位域),该值将转换为int; 否则,它将转换为unsigned int。 这些被称为整数促销

因此对于C,至少将char默认提升为intunsigned int