C ++ 11 Variable narrowing with no GCC compiler warning

The concept of narrowing seems pretty straightforward. However, can someone explain why some of the code below leads to a "narrowing" of the compiler errors, while others do not?

This code generates the expected errors:

constexpr int a = 255; unsigned char b = a; // OK unsigned char c = a + 1; // Error... expected 

This code does not cause errors, but may be in order:

 int d = 256; unsigned char e = d; // Maybe OK because 'd' is not constexpr 

This code should generate errors (if I am missing something):

 int f = 42.0; // Maybe OK because no fractional part int g = 42.1; // OK... should fail!! constexpr float h = 42.7; int i = h; // OK... should fail??? 

I am using g ++ 4.6.2. I searched the GCC error database and did not find anything related. Thanks!

+4
source share
3 answers

Honestly, with your samples, I see little wrong.

However, there are a number of cases where the compiler apparently accepts "violations" of the standard conversion rules ...:

Initializer Lists (Β§ 8.5.4)

However, I noticed this in the standard:

For initial lists is not permissible (Β§ 8.5.4, under 3. )

 int ai[] = { 1, 2.0 }; // error narrowing 

Section 6. The following is a general list of examples:

[Note. As indicated above, such conversions are not allowed at the top level in the initialization list.-End note]

 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 

Interestingly, g ++ 4.6.1 with --std=c++0x -Wall -pedantic catches only one of these violations:

  char c3{y}; // warning: overflow in implicit constant conversion [-Woverflow] 

Outside of initializer lists ...

I do not think that truncating a float in an int is considered narrowing .

This is just a well-defined transformation, similar to

 int i = 31; i /= 4; // well defined loss of precision... i /= 4.0; // equally well-defined conversion from floating point to int 
+9
source

Floating points can be converted to ints:

The class value of the deviating point can be converted to a prvalue of integer type. Convert trun- cates; those. the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.

 int f = 42.0; // Equal to 42, 42 fits into int int g = 42.1; // Equal to 42, 42 fits constexpr float h = 42.7; int i = h; // 42 

A rule restriction applies only to initializer lists.

 unsigned char c = { 2.4 }; // narrowing warning: narrowing conversion of '2.3999999999999999e+0' from 'double' to 'unsigned char' inside { } [-Wnarrowing] 
+1
source

This code generates the expected errors:

 constexpr int a = 255; unsigned char b = a; // OK unsigned char c = a + 1; // Error... expected 

This leads to a narrowing error because:
1. (a + 1) leads to int rvalue
2. rvalue does not match a valid char range

 int d = 256; unsigned char e = d; // Maybe OK because 'd' is not constexpr 

This code is not a narrowing of the rvalue. This is an implicit translation from int to unsigned char.

0
source

Source: https://habr.com/ru/post/1382798/


All Articles