문맥
원래 PIC 마이크로 컨트롤러 용 8 비트 C 컴파일러를 사용하여 컴파일 된 C 코드를 포팅하고 있습니다. 부호없는 전역 변수 (예 : 오류 카운터)가 0으로 롤오버되는 것을 방지하기 위해 사용 된 일반적인 관용구는 다음과 같습니다.
if(~counter) counter++;
여기서 비트 연산자는 모든 비트를 반전 시키며 명령문은 counter
최대 값보다 작은 경우에만 참 입니다. 중요한 것은 변수 크기에 관계없이 작동합니다.
문제
현재 GCC를 사용하여 32 비트 ARM 프로세서를 대상으로하고 있습니다. 우리는 동일한 코드가 다른 결과를 생성한다는 것을 알았습니다. 우리가 알 수있는 한, 비트 보수 연산은 우리가 예상했던 것과 다른 크기의 값을 반환하는 것처럼 보입니다. 이것을 재현하기 위해 GCC에서 컴파일합니다.
uint8_t i = 0;
int sz;
sz = sizeof(i);
printf("Size of variable: %d\n", sz); // Size of variable: 1
sz = sizeof(~i);
printf("Size of result: %d\n", sz); // Size of result: 4
출력의 첫 번째 줄에서 우리 i
는 1 바이트입니다. 그러나 비트 단위의 보수 i
는 실제로 4 바이트 이므로이 문제와 비교하면 예상 한 결과를 얻지 못하므로 문제가 발생합니다. 예를 들어, i
제대로 초기화 된 uint8_t
경우 :
if(~i) i++;
i
0xFF에서 다시 0x00으로 "랩핑" 이 표시됩니다 . 이 동작은 이전 컴파일러와 8 비트 PIC 마이크로 컨트롤러에서 의도했던대로 작동 할 때와 비교하여 GCC에서 다릅니다.
다음과 같이 캐스팅하여이 문제를 해결할 수 있습니다.
if((uint8_t)~i) i++;
또는
if(i < 0xFF) i++;
그러나이 해결 방법 모두에서 변수의 크기를 알고 있어야하며 소프트웨어 개발자에게 오류가 발생하기 쉽습니다. 이러한 종류의 상한 검사는 코드베이스 전체에서 발생합니다. 이 변수의 여러 크기는 (예., uint16_t
과 unsigned char
등)와 달리 작업 코드베이스에서 이러한 변화는 우리가 기대하고있는 것이 아닙니다.
질문
문제에 대한 이해가 올 바르며이 관용구를 사용한 각 사례를 다시 방문하지 않아도되는 문제를 해결하기위한 옵션이 있습니까? 비트 단위 보수와 같은 연산이 피연산자와 동일한 크기의 결과를 반환해야한다는 가정이 맞습니까? 프로세서 아키텍처에 따라 이것이 깨질 것 같습니다. 나는 미친 약을 복용하고 있다고 느끼고 C는 이것보다 조금 이식성이 있어야합니다. 다시 말하지만, 이것에 대한 우리의 이해는 틀릴 수 있습니다.
표면적으로 이것은 큰 문제처럼 보이지 않을 수도 있지만 이전에 작동했던이 관용구는 수백 곳에서 사용되며 값 비싼 변경을 진행하기 전에이를 이해하기를 간절히 바라고 있습니다.
참고 : 여기에는 겉으로는 비슷하지만 정확한 중복 질문이 있습니다 : char의 비트 단위 연산은 32 비트 결과를 제공합니다
나는 거기에서 논의 된 문제의 실제 요점을 보지 못했습니다. 즉 비트 보완의 결과 크기가 연산자에 전달 된 것과 다릅니다.