问题
A byte of data is being stored in a 'char' member variable. It should probably be stored as an 'unsigned char' instead, but that can't be changed. I need to retrieve it through an 'int' variable, but without propagating the sign bit.
My solution was this (UINT and UCHAR are the obvious types):
void Foo::get_data( int *val )
{
if( val )
*val = (int)(UINT)(UCHAR)m_data; // 'm_data' is type 'char'
}
This seemed the best solution to me. I could use
*val = 0xff & (int)m_data;
instead of the casting, but this doesn't seem as readable. Which alternative is better, if either, and why?
回答1:
Just write
*val = (UCHAR)m_data;
As now the expression (UCHAR)m_data
has an unsigned type neither sign bit will be propagated.
回答2:
The cast is better because some compilers (eg. clang) actually generate extra code for the bitwise and. Of course, you only need the one cast to unsigned char
.
The cast also expresses your intent better: the data is actually an unsigned char that you move to an int. So I would call it better even with compilers which generate the same code.
回答3:
The type of conversion here is Integral promotion.
When promoting to a wider integer type the value is always "widened" using its signedness, so that the sign is propagated to the new high order bits for signed values. To avoid the sign propagation convert a signed value to its corresponding unsigned type first.
You can do that with an explicit *val = static_cast<UCHAR>(m_data)
.
Or, safer, using as_unsigned
function as *val = as_unsigned(m_data)
. Function as_unsigned
looks like:
inline unsigned char as_unsigned(char a) { return a; }
inline unsigned char as_unsigned(unsigned char a) { return a; }
inline unsigned char as_unsigned(signed char a) { return a; }
// And so on for the rest of integer types.
Using as_unsigned
eliminates the risk of that explicit cast becoming incorrect after maintenance, should m_data
become a wider integer it will use another overload of as_unsigned
automatically without requiring the maintainer to manually update the expression. The inverse function as_signed
is also useful.
来源:https://stackoverflow.com/questions/45176562/converting-char-to-int-without-sign-bit-propagation-in-c