부호있는 문자에서 부호없는 문자로 변환하고 다시 되 돌리시겠습니까?
저는 JNI로 작업하고 있으며 jbyte 유형의 배열을 가지고 있습니다. 여기서 jbyte는 -128에서 127까지의 부호있는 문자로 표시됩니다. jbyte는 이미지 픽셀을 나타냅니다. 이미지 처리를 위해 일반적으로 픽셀 구성 요소의 범위는 0에서 255까지입니다. 따라서 jbyte 값을 0에서 255까지의 범위 (즉, 부호없는 문자와 동일한 범위)로 변환하고 값에 대해 몇 가지 계산을 수행 한 다음 결과는 다시 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
경우 값 128로 평가해야합니다. , 비트 값 255 0b11111111
이면 reinterpret_cast로 수행됩니다.
이제, 2의 보수 표현의 경우 이것은 정확히 같은 일이됩니다. 왜냐하면 -128은로 표현 0b10000000
되고 -1은 그 0b11111111
사이의 모든 것에 대해 마찬가지로 표현되기 때문 입니다. 그러나 다른 컴퓨터 (일반적으로 오래된 아키텍처)는 부호 및 크기 또는 보완과 같은 다른 부호 표현을 사용할 수 있습니다. ones의 보수에서 0b10000000
bitvalue는 -128이 아니라 -127이 될 것입니다. 그래서 unsigned char에 대한 정적 캐스트는 이것을 129로 만들고 reinterpret_cast는 이것을 128로 만들 것입니다.0b11111111
bitvalue는 -1이 아니라 -0입니다 (예,이 값은 1의 보수에 있음). static_cast를 사용하면 0 값으로 변환되지만 reinterpret_cast를 사용하면 255 값으로 변환됩니다. 1의 보수의 경우 부호없는 128의 값은 -0 값으로 인해 -127에서 127까지의 범위이므로 실제로 부호있는 문자로 표시 할 수 없습니다.
대부분의 컴퓨터가 2의 보수를 사용하여 코드가 실행될 거의 모든 곳에서 전체 문제를 논할 것이라고 말해야합니다. 매우 오래된 아키텍처에서 2 개의 보완 물이 아닌 시스템을 볼 수있을 것입니다. 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 언어는 정수 승격이라는 기능을 사용하여 계산을 수행하기 전에 값의 비트 수를 늘립니다. 따라서 CLAMP255 매크로는 정수 (아마 32 비트) 정밀도로 작동합니다. 결과는 jbyte에 할당되어 정수 정밀도를 jbyte에 맞는 8 비트로 다시 줄입니다.
CLAMP255는 v <0에 대해 0을 반환하고 v> = 0에 대해 255를 반환한다는 것을 알고 있습니까?
IMHO, CLAMP255는 다음과 같이 정의되어야합니다.
#define CLAMP255(v) (v > 255 ? 255 : (v < 0 ? 0 : v))
차이 : v가 255보다 크지 않고 0보다 작지 않은 경우 : 255 대신 v를 반환합니다.
입력 데이터를 해석하는 방법에는 두 가지가 있습니다. -128이 가장 낮은 값이고 127이 가장 높은 값 (즉, 실제 서명 된 데이터)이거나, 0이 가장 낮은 값이고, 127이 중간 어딘가에 있고, 다음 "높은"숫자가 -128이고 -1이 "최고"값 (즉, 최상위 비트는 이미 2의 보수 표기법에서 부호 비트로 잘못 해석되었습니다.
후자를 의미한다고 가정하면 공식적으로 올바른 방법은
signed char in = ...
unsigned char out = (in < 0)?(in + 256):in;
적어도 gcc가 no-op으로 올바르게 인식합니다.
나는 당신의 질문을 이해한다고 100 % 확신하지 못하므로, 내가 틀렸다면 말해주세요.
내가 맞으면 기술적으로 서명 된 문자이지만 실제로 는 0에서 255까지의 픽셀 값인 jbyte를 읽고 있으며 프로세스에서 값을 손상시키지 않고 어떻게 처리해야하는지 궁금합니다.
Then, you should do the following:
convert jbytes to unsigned char before doing anything else, this will definetly restore the pixel values you are trying to manipulate
use a larger signed integer type, such as int while doing intermediate calculations, this to make sure that over- and underflows can be detected and dealt with (in particular, not casting to a signed type could force to compiler to promote every type to an unsigned type in which case you wouldn't be able to detect underflows later on)
when assigning back to a jbyte, you'll want to clamp your value to the 0-255 range, convert to unsigned char and then convert again to signed char: I'm not certain the first conversion is strictly necessary, but you just can't be wrong if you do both
For example:
inline int fromJByte(jbyte pixel) {
// cast to unsigned char re-interprets values as 0-255
// cast to int will make intermediate calculations safer
return static_cast<int>(static_cast<unsigned char>(pixel));
}
inline jbyte fromInt(int pixel) {
if(pixel < 0)
pixel = 0;
if(pixel > 255)
pixel = 255;
return static_cast<jbyte>(static_cast<unsigned char>(pixel));
}
jbyte in = ...
int intermediate = fromJByte(in) + 30;
jbyte out = fromInt(intermediate);
ReferenceURL : https://stackoverflow.com/questions/5040920/converting-from-signed-char-to-unsigned-char-and-back-again
'IT TIP' 카테고리의 다른 글
리플렉션 (Java)을 사용하여 개인 정적 메서드를 어떻게 호출합니까? (0) | 2020.12.15 |
---|---|
setup.py 및 / bin /에 파일 추가 (0) | 2020.12.15 |
다른 TransactSQL 스크립트를 실행하기위한 TransactSQL (0) | 2020.12.15 |
항상 키워드 인수를 사용하지 않는 이유가 있습니까? (0) | 2020.12.15 |
스칼라 객체 유형에 대한 classOf를 얻는 방법 (0) | 2020.12.15 |