Converting from signed char to unsigned char and back again?

I'm working with JNI and have an array of type jbyte, where jbyte is represented as an signed char ie ranging from -128 to 127. The jbytes represent image pixels. For image processing, we usually want pixel components to range from 0 to 255. I therefore want to convert the jbyte value to the range 0 to 255 (ie the same range as unsigned char), do some calculations on the value and then store the result as a jbyte again.

How can I do these conversion safely?

I managed to get this code to work, where a pixel value is incremented by 30 but clamped to the value 255, but I don't understand if it's safe or portable:

 #define CLAMP255(v) (v > 255 ? 255 : (v < 0 ? 0 : v))

 jbyte pixel = ...
 pixel = CLAMP_255((unsigned char)pixel + 30);

I'm interested to know how to do this in both C and C++.


This is one of the reasons why C++ introduced the new cast style, which includes static_cast and reinterpret_cast

There's two things you can mean by saying conversion from signed to unsigned, you might mean that you wish the unsigned variable to contain the value of the signed variable modulo the maximum value of your unsigned type + 1. That is if your signed char has a value of -128 then CHAR_MAX+1 is added for a value of 128 and if it has a value of -1, then CHAR_MAX+1 is added for a value of 255, this is what is done by static_cast. On the other hand you might mean to interpret the bit value of the memory referenced by some variable to be interpreted as an unsigned byte, regardless of the signed integer representation used on the system, ie if it has bit value 0b10000000 it should evaluate to value 128, and 255 for bit value 0b11111111 , this is accomplished with reinterpret_cast.

Now, for the two's complement representation this happens to be exactly the same thing, since -128 is represented as 0b10000000 and -1 is represented as 0b11111111 and likewise for all in between. However other computers (usually older architectures) may use different signed representation such as sign-and-magnitude or ones' complement. In ones' complement the 0b10000000 bitvalue would not be -128, but -127, so a static cast to unsigned char would make this 129, while a reinterpret_cast would make this 128. Additionally in ones' complement the 0b11111111 bitvalue would not be -1, but -0, (yes this value exists in ones' complement,) and would be converted to a value of 0 with a static_cast, but a value of 255 with a reinterpret_cast. Note that in the case of ones' complement the unsigned value of 128 can actually not be represented in a signed char, since it ranges from -127 to 127, due to the -0 value.

I have to say that the vast majority of computers will be using two's complement making the whole issue moot for just about anywhere your code will ever run. You will likely only ever see systems with anything other than two's complement in very old architectures, think '60s timeframe.

The syntax boils down to the following:

signed char x = -100;
unsigned char y;

y = (unsigned char)x;                    // C static
y = *(unsigned char*)(&x);               // C reinterpret
y = static_cast<unsigned char>(x);       // C++ static
y = reinterpret_cast<unsigned char&>(x); // C++ reinterpret

To do this in a nice C++ way with arrays:

jbyte memory_buffer[nr_pixels];
unsigned char* pixels = reinterpret_cast<unsigned char*>(memory_buffer);

or the C way:

unsigned char* pixels = (unsigned char*)memory_buffer;

Yes this is safe.

The c language uses a feature called integer promotion to increase the number of bits in a value before performing calculations. Therefore your CLAMP255 macro will operate at integer (probably 32 bit) precision. The result is assigned to a jbyte, which reduces the integer precision back to 8 bits fit in to the jbyte.


Do you realize, that CLAMP255 returns 0 for v < 0 and 255 for v >= 0?
IMHO, CLAMP255 should be defined as:

#define CLAMP255(v) (v > 255 ? 255 : (v < 0 ? 0 : v))

Difference: If v is not greater than 255 and not less than 0: return v instead of 255

链接地址: http://www.djcxy.com/p/96702.html

上一篇: C ++字符类型的长度和大小

下一篇: 从signed char转换为unsigned char并返回?