Sla*_*zer 22 c++ types type-conversion integer-promotion c++11
为什么unsigned short * unsigned short
转换为int
C++ 11?
在int
太小的这行代码为证明办理最大值.
cout << USHRT_MAX * USHRT_MAX << endl;
Run Code Online (Sandbox Code Playgroud)
在MinGW 4.9.2上溢出
-131071
Run Code Online (Sandbox Code Playgroud)
因为(来源)
USHRT_MAX = 65535(2 ^ 16-1)或更高*
INT_MAX = 32767(2 ^ 15-1)或更高*
和(2^16-1)*(2^16-1) = ~2^32
.
我应该期待这个解决方案有什么问题吗?
unsigned u = static_cast<unsigned>(t*t);
Run Code Online (Sandbox Code Playgroud)
这个计划
unsigned short t;
cout<<typeid(t).name()<<endl;
cout<<typeid(t*t).name()<<endl;
Run Code Online (Sandbox Code Playgroud)
给出输出
t
i
Run Code Online (Sandbox Code Playgroud)
上
gcc version 4.4.7 20120313 (Red Hat 4.4.7-16) (GCC)
gcc version 4.8.2 (GCC)
MinGW 4.9.2
Run Code Online (Sandbox Code Playgroud)
既
g++ p.cpp
g++ -std=c++11 p.cpp
Run Code Online (Sandbox Code Playgroud)
这证明了t*t
转换为int
这些编译器.
https://bytes.com/topic/c-sharp/answers/223883-multiplication-types-smaller-than-int-yields-int
http://www.cplusplus.com/reference/climits
http://en.cppreference.com/w/cpp/language/types
编辑:我已经在下面的图像上演示了这个问题.
Som*_*ude 12
小整数类型的Prvalues(例如
char)
可以转换为较大整数类型的prvalues(例如int
).特别是,算术运算符不接受小于int
参数的类型
上面所说的是,如果你在一个涉及算术运算符的表达式中使用小于int
(like unsigned short
)的东西(当然包括乘法),那么值将被提升为.int
Che*_*Alf 10
这是通常的算术转换.
通常称为论证推广,虽然该标准以更受限制的方式使用该术语(合理描述性术语与标准术之间的永恒冲突).
C++11§5/ 9:"许多期望算术或枚举类型操作数的二元运算符会以类似的方式引起转换并产生结果类型.目的是产生一个通用类型,它也是结果的类型.这种模式称为通常的算术转换 [...]
该段继续描述细节,这些细节相当于转换为更一般类型的阶梯,直到所有参数都可以表示.此梯形图中的最低梯级是二进制操作的两个操作数的整体提升,因此至少执行该操作(但转换可以从更高的梯级开始).积分促销从这开始:
C++11§4.5/ 1:"以外的整数类型的prvalue
bool
,char16_t
,char32_t
,或wchar_t
,其整数转换秩(4.13)小于的秩int
可以被转换成类型的prvalueint
如果int
可以表示源类型的所有值; 否则,源prvalue可以转换为类型的prvalueunsigned int
至关重要的是,这是关于类型,而不是算术表达式.在您的情况下,乘法运算符的参数*
将转换为int
.然后乘法作为乘法执行int
,产生int
结果.
正如Paolo M在评论中所指出的那样,USHRT_MAX
有类型int
(这由5.2.4.2.1/1指定:所有这些宏的类型至少与其一样大int
).
所以USHRT_MAX * USHRT_MAX
已经是int
x int
,没有促销活动.
这将在您的系统上调用有符号整数溢出,从而导致未定义的行为.
关于提议的解决方案:
unsigned u = static_cast<unsigned>(t*t);
Run Code Online (Sandbox Code Playgroud)
这没有用,因为t*t
它本身会因有符号整数溢出而导致未定义的行为.正如其他答案所解释的那样,由于历史原因,在乘法发生之前t
被提升int
.
相反,你可以使用:
auto u = static_cast<unsigned int>(t) * t;
Run Code Online (Sandbox Code Playgroud)
其中,后整数推广,被一个unsigned int
乘以一个int
; 然后根据通常的算术转换的其余部分,将int
其提升为unsigned int
,并且发生明确定义的模乘.
归档时间: |
|
查看次数: |
4619 次 |
最近记录: |