2012-12-09 3 views
1

나는이 정확한 행동에 대답하는 질문을 찾지 못했습니다. 어떻게 된 일인지 이해하지 못했습니다.C/C++ : char []의 int 변환이 실패하고, unsigned char []가 int로 변환됩니다. 이유는 무엇입니까?

Windows 비트 맵 파일 (bmp)의 내용을 배열로 읽고이 배열을 사용합니다 이 후

char biHeader[40]; 
// ... 
source.read(biHeader,40); 
// ... 
int biHeight = biHeader[8] | (biHeader[9] << 8) | (biHeader[10] << 16) | (biHeader[11] << 24); 

, 그것은 400을해야하기 때문에 완전히 잘못 -112biHeight 쇼 : 나중에 필요한 정보를 추출합니다. 그래서 파일의 16 진수 덤프를 살펴 보았습니다. 읽은 내용은 다음과 같습니다 예상대로 큰 엔디안 바이트 순서를 변경

90 01 00 00 

, 진수 400입니다 0x190을 제공합니다.

내가에 위의 코드를 변경하는 경우 :

unsigned char biHeader[40]; 
// ... 
source.read((char*)biHeader,40); 
// ... 
int biHeight = ... (same as before) 

... 그럼 내가 예상 가치를 얻을. 여기서 무슨 일이 일어나고있는거야?

그리고이 데이터를 어떻게 읽으시겠습니까?

+0

한 가지 더 : 값이 음수 일 수 있으므로 int로 변환해야하며 부호없는 int로 변환해야합니다! –

+0

일반적으로 BITMAPINFOHEADER는 구조체로 읽 힙니다. 여기서 biHeight는 Windows 플랫폼에서 LONG입니다. 적어도 – Chubsdad

+0

이 헤더의 여러 버전 (끝으로 다른 필드가 있음)이 있기 때문에 구조체로 읽지 않기로했습니다. LONG? 파일 형식 정의에 따르면 이것은 잘못된 것입니다. 또는 더 구체적으로 : biHeight는 4 바이트로 구성됩니다 (길이는 8 바이트가 될 수 있음) –

답변

4

부호가있는 8 비트 2의 보수 정수로 0x90-112입니다. 이 값을 |에 대해 int으로 변환하면 해당 값이 보존됩니다. 일곱 번째의 모든 비트는 표현이 2의 보수 인 경우 설정되므로 비트 또는 8 비트 이상 왼쪽으로 시프트 한 값을 사용하면 더 이상 값이 변경되지 않습니다.

부호없는 8 비트 정수로, 0x90의 값은 144이며, 2^7 비트 세트를 초과하는 비트가없는 양수입니다. 그런 다음 비트 단위로 또는 biHeader[9] << 8으로 값을 원하는 144 + 256 = 400으로 변경합니다.

비트 연산자를 사용할 때 (거의 항상) 부호없는 유형을 사용하면 부호가있는 유형은 종종 불쾌한 놀라움을 가져옵니다 (시프트 결과가 범위를 벗어나거나 음수를 왼쪽으로 이동하면 정의되지 않은 동작이 발생합니다).

+0

아, 감사합니다. 그건 완전히 의미가 있습니다. 그래서 나는 그것을 부호없는 char []로 계속 읽는다. –

+0

이 코드에는'biHeader [11] << 24'가 포함되어 있는데, 이는 biHeader [11]을 암시 적으로 int로 변환하고 24 비트를 이동시킵니다. 따라서 C 표준은'biHeader [11]'이 128 이상이고'int'가 32 비트 일 때 동작을 정의하지 않습니다. 이 코드는'int' 결과를 원하기 때문에 컴파일러가이 경우에 대한 동작이나 특수 처리에 대한 보증 또는'biHeader [11]'이 절대로 128 이상이되지 않도록 보장해야합니다. –

+0

필자의 "주요 문제"는 컴파일러가 값을 해석하려고 시도한다는 것입니다. 배열 내부의 값을 (little endian에서 big endian으로) 정렬 한 다음 메모리의 올바른 위치에 int 포인터를 사용하는 것이 좋습니다. –

관련 문제