从signed char转换为unsigned char并再次返回?

rbc*_*bcc 59 c c++ java-native-interface

我正在使用JNI并且有一个jbyte类型的数组,其中jbyte表示为有符号字符,即-128到127.jbytes表示图像像素.对于图像处理,我们通常希望像素分量的范围为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);
Run Code Online (Sandbox Code Playgroud)

我很想知道如何在C和C++中做到这一点.

wic*_*ich 109

这是C++引入新的强制转换风格的原因之一,包括static_castreinterpret_cast

你可以通过说明从有符号到无符号的转换来表示两件事,你可能意味着你希望无符号变量包含有符号变量的值,模数为无符号类型的最大值+ 1.这就是你的签名字符有一个值为-128然后CHAR_MAX+1添加为值128,如果值为-1,则CHAR_MAX+1添加值为255,这是static_cast所做的.另一方面,您可能意味着将某个变量引用的内存的位值解释为无符号字节,而不管系统上使用的有符号整数表示,即如果它具有位值0b10000000,则应评估为值128 ,对于位值为255 0b11111111,这是通过reinterpret_cast完成的.

现在,对于二进制补码表示,这恰好是完全相同的事情,因为-128表示为0b10000000,-1表示为,0b11111111并且同样表示它们之间的所有.然而,其他计算机(通常是较旧的架构)可能使用不同的签名表示,例如符号和数字或补码.在补码中,0b10000000bitvalue不会是-128,而是-127,所以静态转换为unsigned char会使这129,而reinterpret_cast会使这128.另外在补码中0b11111111bitvalue不会是-1,但是-0,(是的,这个值存在于'的补码中),并且将使用static_cast转换为值0,但使用reinterpret_cast将值转换为255.请注意,在1的补码的情况下,无符号值128实际上不能用有符号的char表示,因为它的范围是-127到127,因为-0值.

我不得不说绝大多数计算机都会使用两个补码,这使得整个问题几乎无处不在.你可能只会在非常古老的架构中看到除了两个补码以外的系统,想想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
Run Code Online (Sandbox Code Playgroud)

要用一个很好的C++方式用数组做到这一点:

jbyte memory_buffer[nr_pixels];
unsigned char* pixels = reinterpret_cast<unsigned char*>(memory_buffer);
Run Code Online (Sandbox Code Playgroud)

或C方式:

unsigned char* pixels = (unsigned char*)memory_buffer;
Run Code Online (Sandbox Code Playgroud)

  • 是的,根据程序的语义,您可以安全地将一个带符号的字符数组转换为指向unsigned char的指针,您可以有效地说,这个内存不是一个有符号字符数组,而是一个无符号字符数组.但请注意,这将是一个reinterpret_cast,而不是静态演员,但从你描述问题的方式来看,我认为重新解释演员是你想要的. (2认同)
  • @serup为什么不真正起作用?这对我来说可以。但是,我的措词会略有不同。`std :: vector &lt;char&gt;缓冲区; 无符号字符* ptr = reinterpret_cast &lt;无符号字符*&gt;(buffer.data()); std :: vector &lt;unsigned char&gt; cache(ptr,ptr + buffer.size());`请注意,这将始终创建缓冲区的副本,而普通数组方法不会。 (2认同)