为啥编译器将“char”匹配到“int”而不是“short”?

Posted

技术标签:

【中文标题】为啥编译器将“char”匹配到“int”而不是“short”?【英文标题】:Why does the compiler match "char" to "int" but not "short"?为什么编译器将“char”匹配到“int”而不是“short”? 【发布时间】:2016-09-07 01:27:56 【问题描述】:

我有一个小程序:

#include<iostream>
using namespace std;

void f(int)    cout << "int\n";   
void f(short)  cout << "short\n"; 

int main(void)
    char c = 0;
    f(c);
    return 0;

它打印int。我觉得,如果这是因为“整数提升”,为什么不首选short

我也知道整数提升发生在表达式中(例如 A=B)。但是我在调​​用f(), 时没有表达对吗?

如果这与重载解析规则有关,为什么将char 传递给 f 会导致编译器更喜欢int 而不是short

如果我删除f(int),那么f(c) 将调用f(short)

总而言之,我的问题是,它与“整数提升”还是“重载解析规则”有关?为什么?

【问题讨论】:

您是否正在尝试解决某个问题,或者这只是出于好奇? (有点可疑) 理由是,int 被认为是最佳处理器/寄存器大小,short 只是一个打包好的内存布局。因此,int(“寄存器”)用于处理char。假设短减法不会比 int 减法更有效。 @JoopEggen - 这不是一个基本原理(可疑或其他),这是一个设计决策:在 C 和 C++ 中,int 应该是架构的自然大小,所以它应该是在没有充分理由偏爱其他事物时使用。 @PeteBecker 我想为该设计决策制定原因。由于已经有引用引用的答案,我不想要一个合法的声明。 好问题+1!!! 【参考方案1】:

(整体)促销优于overload resolution的其他(整体)转化

隐式转换序列的排名

1) 精确匹配:无需转换、左值到右值转换、限定转换、函数指针转换、(C++17 起)用户定义的类类型到同一类的转换

2)提升:积分提升、浮点提升

3) 转换:整型转换、浮点型转换、浮点型整型转换、指针转换、指针到成员的转换、布尔转换、派生类到它的用户定义的转换基地

因此,从charint 的提升优于从charshort 的转换。


什么是促销?你可能会问。它是标准描述的一种特殊的转换。

为什么charshort 不是促销活动?,你可以继续。 Integral promotion 始终为 int 或更大的类型。 short 没有任何促销活动。

以下隐式转换被归类为整数提升:

signed char 或signed short 可以转换为int;

如果 unsigned char 或 unsigned short 可以保存其整个值范围,则可以转换为 int,否则可以转换为 unsigned int;

char 可以转换为 int 或 unsigned int,具体取决于底层类型:signed char 或 unsigned char(见上文);

wchar_t、char16_t 和 char32_t 可以转换为以下列表中的第一个能够保存其整个值范围的类型:int、unsigned int、long、unsigned long、long long、unsigned long long; 可以将其基础类型不固定的无范围枚举类型转换为以下列表中的第一个能够保存其整个值范围的类型:int、unsigned int、long、unsigned long、long long 或 unsigned long long。如果值范围更大,则不适用积分促销;

基础类型固定的无作用域枚举类型可以转换为其提升的基础类型;

(C++11 起)

如果位域类型可以表示位域的整个取值范围,则可以转换为 int,如果可以表示位域的整个取值范围,则可以转换为 unsigned int,否则不适用整数提升; bool 类型可以转换为 int,值 false 变为​0​,true 变为 1。


标准参考(当前标准草案):

[over.ics.scs] § 3

[conv.prom] § 1

【讨论】:

为什么字面量 0 被视为 char 而不是整数类型? @shasan Literal 0 不被视为字符。它(通常)被“感知”为 int。另外,char 一个整数类型。 在原始问答的上下文中再次查看我的问题。问题询问为什么使用0 的函数调用会调用int 重载。答案解释了“从 char 到 int 的提升优于从 char 到 short 的转换”。 The question asks why the function call with 0 calls the int overload. 不,它没有。它询问为什么用c 调用重载函数会选择int 重载而不是shortc 不是文字 0;它是一个char 左值。原因是一种转化(促销)比另一种转化(非促销)更受欢迎。【参考方案2】:

来自Implicit conversion(cppreference):

以下隐式转换被归类为整数提升:

[...] char 可以根据底层类型转换为 intunsigned intsigned charunsigned char(见上文); [...]

所以,如果有函数f(int)f(short),编译器会先尝试做一个整数提升,如果不行,就会回退到一个整数转换.

charint 是一个整数提升(见上文),所以编译器会选择它。

如果没有任何f(int),编译器将无法找到可以进行整数提升的函数,并将回退到整数转换。它找到了f(short),而char可以转换成short,所以它会选择它。

【讨论】:

在确定整数提升和转换之间的区别时,为什么他们在列表本身中使用“转换”一词?这似乎是歧义/混淆的潜在来源,尤其是在引用时。 @JAB 好问题 :) 我认为他们的意思是促销是一种特殊类型的转换。但因为它仍然是一种转换,所以他们部分地这样称呼它 他们确实确定整体促销在报价开始时属于隐式转换的范畴,所以这是有道理的。

以上是关于为啥编译器将“char”匹配到“int”而不是“short”?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 putchar、toupper、tolow 等采用 int 而不是 char?

无法将 128 分配给字节,为啥它会出错而不是溢出?

ANSI C:为啥字符函数接受 int 参数而不是 char 参数?

为啥将“0”添加到 int 数字允许转换为 char?

为啥将字符串作为文件名而不是 char* 传递时出现错误?

为啥 atoi 函数不能将 const char * 转换为 int?