为什么是“unsigned int ui = {-1};”缩小转换误差? [英] Why is "unsigned int ui = {-1};" a narrowing conversion error?

查看:1082
本文介绍了为什么是“unsigned int ui = {-1};”缩小转换误差?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

第8.5.4 / 7节的标准说明了缩小转换的原因:


转换是隐式转换



- 从浮点类型到整数类型,或



long double到double或float,或者从double到float,除非源是常量
表达式,转换后的实际值在可以表示的值的范围内
(即使它不能正确表示)或



- 从整数类型或无范围的枚举类型到浮点类型,除非源
是常量表达式,转换后的实际值将适合目标类型,并且当转换回原始类型时将
产生原始值,或者从整数类型转换为



或无范围枚举类型转换为不能表示原始类型的所有
值的整数类型,除非源是常量表达式,并且
转换后的实际值将适合目标类型,并且将产生


然后它在一些列表初始化上下文中禁止这样的转换,给出
示例:


[注意:如上所述,列表初始化中不允许在顶级进行此类转换。 - end
note] [示例:




  int x = 999; // x不是常量表达式
const int y = 999;
const int z = 99;
char c1 = x; // OK,尽管它可能会变窄(在这种情况下,它变窄)
char c2 {x}; //错误:可能狭窄
char c3 {y}; // error:narrows(假设char是8位)
char c4 {z}; // OK:no narrowing needed
unsigned char uc1 = {5}; // OK:no narrowing needed
unsigned char uc2 = {-1}; // error:narrows
unsigned int ui1 = {-1}; //错误:narrows
signed int si1 =
{(unsigned int)-1}; // error:narrows
int ii = {2.0}; // error:narrows
float f1 {x}; // error:might narrow
float f2 {7}; // OK:7可以正确表示为float
int f(int);
int a [] =
{2,f(2),f(2.0)}; // OK:double-to-int转换不在顶层




- end example]


示例中显示的所有7个错误都由
clang 3.2 /3.3与 -std = c ++ 11 ,例如

 错误:非常量表达式在初始化器列表中不能从类型'int'变为'char'[-Wc ++ 11-narrowing] 

没有一个被gcc 4.7.2 / 4.8.1报告为错误,但是在每种情况下都给出类似的警告,例如

 警告:缩小'x'从'int'到'char'内部的转换{} [-Wnarrowing] 
pre>

(因此gcc似乎知道合规需要什么,但默认允许不合规
。)



我不明白的是如何示例:

  unsigned int ui1 = {-1} //错误:narrows 

符合范例。 (类似地,对称的 si1 示例。)显然
只有它可以限定为示例的词是第四个
和上面给出的缩小转换定义中的最终项目;但是
如果是这样,为什么示例不能通过资格转义
,除非源是常量表达式,而
转换后的实际值将适合目标类型,并且当转换回
原始类型时会产生原始值?
?当然 -1 有一个整数常量,如果转换为 unsigned ,然后返回,
仍然会产生 int -1



我失踪了什么?

解决方案


当然-1有一个整数常量,如果转换为unsigned和back,仍然会产生int -1?


这是错误的。如果将-1转换为 unsigned ,您将获得 UINT_MAX 。这很好,因为转换为无符号类型总是定义的。但是, UINT_MAX 不适用于 int ,转换为有符号类型只有在该值适合时才由标准定义目标类型。


The Standard at § 8.5.4/7 explains what a narrowing conversion is:

A narrowing conversion is an implicit conversion

— from a floating-point type to an integer type, or

— from long double to double or float, or from double to float, except where the source is a constant expression and the actual value after conversion is within the range of values that can be represented (even if it cannot be represented exactly), or

— from an integer type or unscoped enumeration type to a floating-point type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type, or

— from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type.

It then disallows such conversions in some list-initialization contexts, giving examples:

[ Note: As indicated above, such conversions are not allowed at the top level in list-initializations. — end note ] [ Example:

int x = 999;        // x is not a constant expression
const int y = 999;
const int z = 99;
char c1 = x;    // OK, though it might narrow (in this case, it does narrow)
char c2{x};     // error: might narrow
char c3{y};     // error: narrows (assuming char is 8 bits)
char c4{z};     // OK: no narrowing needed
unsigned char uc1 = {5};    // OK: no narrowing needed
unsigned char uc2 = {-1};   // error: narrows
unsigned int ui1 = {-1};    // error: narrows
signed int si1 =
{ (unsigned int)-1 };   // error: narrows
int ii = {2.0};         // error: narrows
float f1 { x };         // error: might narrow
float f2 { 7 };         // OK: 7 can be exactly represented as a float
int f(int);
int a[] =
{ 2, f(2), f(2.0) }; // OK: the double-to-int conversion is not at the top level

— end example ]

All 7 of the errors illustrated by the examples are reported as such by clang 3.2/3.3 with -std=c++11, e.g.

error: non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list [-Wc++11-narrowing]

None of them are reported as errors by gcc 4.7.2/4.8.1, but in each case a similar warning is given, e.g.

warning: narrowing conversion of ‘x’ from ‘int’ to ‘char’ inside { } [-Wnarrowing]

(so gcc seems to know what compliance requires but opts to tolerate non-compliance by default.)

What I do not understand is how the example:

unsigned int ui1 = {-1};    // error: narrows

qualifies as an example. (Likewise with the symmetrical si1 example.) Evidently the only words by which it might qualify as example are those of the fourth and final item in the definition of narrowing conversion given above; but if so then why does the example not escape by the qualification except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type? Surely -1 there is an integer constant and, if converted to unsigned and back, still yields int -1?

What am I missing?

解决方案

Surely -1 there is an integer constant and, if converted to unsigned and back, still yields int -1?

This is wrong. If you convert -1 to unsigned you get UINT_MAX. This is fine because converting to unsigned types is always defined. However, UINT_MAX does not fit in int and conversions to signed types are only defined by the standard when the value fits in the target type.

这篇关于为什么是“unsigned int ui = {-1};”缩小转换误差?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆