2017-10-31 15 views
1

GCC를 사용하여 컴파일 된 소형 ARM 프로세서 용 소프트웨어를 작성할 때 기발한 문제가 발생했습니다. 프로세서에는 하드웨어 디비전 엔진이 없으므로 소프트웨어에서 디비전을 구현합니다. Z에 대한 인쇄C에서 타입 혼합 정수 나누기 : 컴파일러 버그 또는 정의 된 동작?

volatile int32_t x = -4000; 
volatile uint32_t y = 4; 
volatile int32_t z = x/y; 

uart_printf(DBG_LVL_INFO, "%d/%d = %d\r\n", x, y, z); 

결과는 1073740824,하지만 난 -1000의 결과를 기대 :

다음 코드

이 동작을 복제, 휘발성 문은 최적화를 방지하기 위해 사용된다.

유형 믹싱이 중요합니다. uint32_tint32_t으로 바꾸면 버그가 해결됩니다.

-1000은 부호없는 정수로 잘못 해석되어 결과가 흥미롭게도 2 에 더한 것으로 나타납니다.

버그입니까, 아니면 정의 된 동작입니까?

답변

6

C에서 수학 연산을 수행 할 때 보다 좁은 유형은 보다 넓게으로 변환됩니다. 귀하의 경우 모든 int32_t 변수는 uint32_t으로 변환되며 이는 프로모션입니다.

-4000uint32_t에 매우 큰 숫자입니다. 실제로, 그것은 대략 40 억 인 0xFFFFFFFF - 4000입니다. 40 억 (및 무언가)을 4로 나누면 결과가 나타납니다. 그것은 단지 int 유형으로 작동하기 때문에,

volatile int32_t z = x/(int32_t)y; 

당신의 결과를 인쇄, %dint32_t 또는 uint32_t이 정의되지 않은 동작입니다 사용하여 :

어디서나 동일한 유형 중 하나를 사용하여 문제를 해결 또는 변수를 사용하기 전에 캐스팅 않는다 .

+0

설명해 주셔서 감사합니다. –

+0

re : printf, 컴파일러는 모든 가변적 인 정수형을 int 형으로 캐스팅하는 것으로 간주하므로 uint32_t 및 friends * should *를 사용하십시오. 그러나 나는 시정을 기다리고 있습니다. –

+0

@TomOldbury 당신은 틀렸다고 믿습니다. long은 varuadic int이지만 % l을 사용해야합니다. – tilz0R