简体   繁体   中英

Narrowing Conversion of unsigned int to short unsigned int

warning: narrowing conversion of '(stride * 4u)' from 'unsigned int' to 'WORD {aka short unsigned int}' inside { } is ill-formed in C++11 [-Wnarrowing]

I cannot figure out why I am getting this warning compiling the following code from MinGW:

unsigned stride = 3;

D3DVERTEXELEMENT9 NORMALELEMENT =
{ 0, stride * sizeof(gs_scalar), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 };
if (useNormals) stride += 3;

It is complaining about the stride * sizeof(gs_scalar) (gs_scalar is float ) inside those braces, but I do not see how this is a narrowing conversion since sizeof returns the number of bytes. I tried changing stride 's data type to WORD, DWORD, CHAR, everything, but I keep getting the same or similar warning.

Look at the definition of D3DVERTEXELEMENT9 :

struct D3DVERTEXELEMENT9 {
  WORD Stream;
  WORD Offset;
  BYTE Type;
  BYTE Method;
  BYTE Usage;
  BYTE UsageIndex;
};

(from http://msdn.microsoft.com/en-us/library/windows/desktop/bb172630%28v=vs.85%29.aspx but removed the typedef things).

Thus your are initializing NORMALELEMENT.Offset with stride * sizeof(gs_scalar) .

The type of sizeof(gs_scalar) is std::size_t which is apparently unsigned int on your platform, and the type of stride is unsigned (ie unsigned int ), so the type of stride * sizeof(gs_scalar) is unsigned int . But the type of NORMALELEMENT.Offset is WORD which is unsigned short .

I guess that on your platform unsigned int is 32-bits wide but unsigned short only 16-bits wide, so this is indeed a narrowing conversion (if the value of stride * sizeof(gs_scalar) can't fit in 16 bits you'll lose data).

Even if you define stride as a WORD , it is promoted to unsigned int in the multiplication with sizeof(gs_scalar) , so the situation keeps the same.

If you're sure that stride * sizeof(gs_scalar) will never be more than USHRT_MAX (ie for you 2 16 −1 ie 65535), which seems likely (in the example it's 3 * 4 ie 12), then you can use a cast (as said by Troy in the comments), eg static_cast<WORD>(stride * sizeof(gs_scalar)) .

stride is unsigned so its value could be too large to fit into an unsigned short . Furthermore sizeof has type std::size_t which is also larger than WORD .

If you make stride a const unsigned , then the compiler can see that the actual value 12 does fit into unsigned short and the error goes away. But if it is not a constant, you need to explicitly guarantee that the calculation will fit because initializers inside braces are not allowed to truncate or overflow. ("Narrowing" refers to losing data, alluding to chopping off digits on one end of a number.)

Just use static_cast< WORD >( … ) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM