char是默认提升的吗?

Ker*_* SB 15 c c++ integer-promotion language-lawyer

这可能是一个愚蠢的问题,但有人可以请为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);
Run Code Online (Sandbox Code Playgroud)

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

cni*_*tar 13

首先,默认参数促销

6.5.2.2

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

现在进行整数促销:

6.3.1.1

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

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

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

所以对于C,至少a char是默认提升为intunsigned int.

  • "因此,对于C,至少有一个char被默认提升为int." - 或者`unsigned int`,在那些`char`是无符号的并且`CHAR_MAX`不能表示为`int`的稀有系统上. (3认同)

Jon*_*ler 8

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以外的整数类型的prvalue bool,char16_t,char32_t,或wchar_t,其整数转换秩(4.13)小于的秩int可以被转换成类型的prvalue int如果int可以表示源类型的所有值; 否则,源prvalue可以转换为类型的prvalue unsigned int.

类型的2甲prvalue char16_t,char32_twchar_t(3.9.1)可以被转换为第一以下类型可以表示其基础类型的所有值的prvalue: ,int,unsigned int,long int, unsigned long int,long long intunsigned long long int.如果没有一个类型的该列表可以代表其基础类型的所有值,类型的prvalue char16_t,char32_twchar_t可转化为它的基本类型的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.

-类型的位字段_Bool,int,signed int,或unsigned int.

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

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


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