我正在使用JNI,并且具有类型为jbyte的数组,其中jbyte表示为有符号字符,即-128至127。jbyte表示图像像素。对于图像处理,我们通常希望像素分量的范围是0到255。因此,我想将jbyte值转换为0到255的范围(即与unsigned char相同的范围),对该值进行一些计算,然后存储结果再次为jbyte。
我如何安全地进行这些转换?
我设法使此代码正常工作,其中像素值增加了30,但固定为255,但是我不知道它是安全还是可移植:
#define CLAMP255(v) (v > 255 ? 255 : (v < 0 ? 0 : v))
jbyte pixel = ...
pixel = CLAMP_255((unsigned char)pixel + 30);
我想知道如何在C和C++中做到这一点。
最佳答案
这是C++引入新的转换样式(包括static_cast
和reinterpret_cast
)的原因之一
说从有符号到无符号的转换有两个含义,这可能意味着您希望无符号变量包含无符号类型的最大值+ 1的有模变量的值。也就是说,如果您的带符号字符有一个值为-128,然后将CHAR_MAX+1
的值添加为128,如果它的值为-1,则将CHAR_MAX+1
的值添加为255,这是static_cast所做的。另一方面,您可能打算将某个变量引用的内存的位值解释为无符号字节,而与系统上使用的有符号整数表示形式无关,即,如果它具有位值0b10000000
,则应求值为value 128和255(对于位值0b11111111
),这是通过reinterpret_cast完成的。
现在,对于两者的补码表示,这恰好是一回事,因为-128表示为0b10000000
,-1表示为0b11111111
,同样,两者之间也是如此。但是,其他计算机(通常是较旧的体系结构)可能会使用不同的带符号表示形式,例如符号和大小或补码。在''s补码中,0b10000000
位值将不是-128,而是-127,因此静态转换为无符号字符将使其变为129,而在reinterpret_cast中将其变为128。此外,在''s'补码中,0b11111111
位值将不会为-1。 ,但为-0,(是,该值以1的补码形式存在),并且将通过static_cast转换为0,但通过reinterpret_cast转换为255。请注意,对于“1”的补码,无符号值128实际上不能用带符号的char表示,因为由于-0值,其范围从-127到127。
我不得不说,绝大多数计算机将使用二进制补码,从而使整个问题几乎可以在您的代码将要运行的任何地方进行。考虑到60年代的时间框架,您可能只会在非常古老的体系结构中看到除二进制补码以外的任何其他系统。
语法可归结为以下内容:
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
要使用数组以一种不错的C++方式执行此操作:
jbyte memory_buffer[nr_pixels];
unsigned char* pixels = reinterpret_cast<unsigned char*>(memory_buffer);
或C方式:
unsigned char* pixels = (unsigned char*)memory_buffer;
关于c++ - 从有符号字符转换为无符号字符然后再次返回?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5040920/