2015-01-05 12 views
0

다음 스 니펫에서 lShift 할당에 대해 MISRA-C : 2004 규칙 10.1 및 10.3 오류가 계속 발생하는 것으로 보이고 요구 사항을 충족하기 위해 더 많은 작업을 수행 할 수 있는지 확인할 수 없습니다 ... 오류가 계속 발생하는 이유는 무엇입니까 ?MISRA-C : 2004에서 왜 여기에 오류가 발생합니까?

#define ADC_INTSELxNy_LOG2_NUMBITS_PER_REG 3U 
#define ADC_INTSELxNy_NUMBITS_PER_REG 8U 
void foo (const bar_e intNumber) { 
    uint_least8_t lShift = (uint_least8_t)(ADC_INTSELxNy_NUMBITS_PER_REG - (((((uint_least8_t)intNumber) + 1U) & 0x1U) << ADC_INTSELxNy_LOG2_NUMBITS_PER_REG)); 
    //... 
} 
+0

규칙 10.1 및 10.3이란 무엇입니까? – mafso

+0

10.1 정수형의 표현식의 값은 A) 동일한 부호의 더 넓은 정수 타입으로의 변환이 아니거나 B) 표현식이 복소수 인 경우 암시 적으로 다른 기본 유형으로 변환되어서는 안된다. C) 표현식이 상수가 아니며 함수 인수이거나 D) 표현식이 상수가 아니며 리턴 표현식입니다. – Toby

+0

10.3 : 정수형의 복합 표현식의 값은 표현의 기본 유형과 동일한 부호가있는 유형으로 만 형변환 될 수 있습니다. – Toby

답변

1

이 줄은 읽을 수없는 엉망입니다. 가독성을 높이기 위해 분할하는 것을 고려하십시오. 시스템에서 int의 너비에 따라 코드가 다르게 보일 것입니다. 아래의 코드는 32 비트 정수를 가정합니다.

uint8_t  bit  = (uint8_t)(((uint32_t)intNumber + 1U) & 0x1U); 
uint32_t  lShift32 = ((uint32_t)bit << ADC_INTSELxNy_LOG2_NUMBITS_PER_REG); 
uint_least8_t lShift8 = (uint_least8_t)((uint32_t)ADC_INTSELxNy_NUMBITS_PER_REG - lShift); 

이제 오류가 발생하는 이유에 대해 규칙 10.1 및 10.3은 암시 적 정수 유형 승격과 관련됩니다. 위와 같이 코드를 분할하면 각 하위 표현식의 기본 유형이 무엇인지 혼란에 빠지게됩니다. 당신이 잘못한 것은 기본 형식 인 에 캐스팅을 추가하는 것입니다.이 작업 전에 작업을 수행하는 것은 좋지 않습니다. 각 작업을 후에 해야합니다.

+ 작업은 + 작업 후 & 작업 및 시프트 연산과 동일한 작업을 수행 한 후 기본 형식 인 으로 명시 적으로 변환해야합니다. 결국 모든 것을 기본 유형으로 변환하는 것만으로는 충분하지 않으며 각 하위 표현식을 개별적으로 고려해야합니다. 첫 번째 행은 intNumber1U과 같은 유형인지 확인 uint32_t에 명시 적 캐스트가 있습니다

:

은 위에서 내 코드를 설명합니다. 이렇게하면 하위 표현식 intNumber + 1U이 암시 적으로 변환되지 않으며 기본 유형 uint8_t와 동일한 서명 유형이 더 넓어집니다 (즉, 안전함을 의미). 추가 결과는 unsigned int 유형입니다. 다시 unsigned int & unsigned int은 암시 적 변환을 생성하지 않습니다. 마지막으로 결과는 uint8_t로 캐스팅되어 여러 가지 MISRA 규칙을 충족시킵니다. 나머지 코드는 동일한 방식으로 진행됩니다.

모든 작업을 단순화하고 암시 적 프로모션을 피하고 서로간에 수많은 캐스트를 피하기 위해 항상 작업 전에 큰 정수 유형으로 확장 캐스트를 시도합니다.

규칙 10.1의 진정한 목적은 실제로 C에서 암시 적 유형 프로모션에 대해 스스로 교육하도록 강요하는 것입니다. 다소 복잡한 주제이지만 무서운 수의 C 프로그래머는 판촉 및 모든 위험을 모르는 것입니다 및 버그로 인해 발생합니다. More info about the type promotion rules here.

+0

마지막 단계를 추가하기 전까지는이 작업이 제대로 작동합니다. (아마도 16 비트 정수를 사용하지 못하고 + 빼기) uint_least8_t lshift8 = (uint_least8_t) (ADC_INTSELxNy_NU_NUMBITS_PER_REG - (uint_least8_t) lShift16);'. 어쩌면 아직 프로모션이 제대로 안되니? – Toby

+0

아, 'uint_least8_t lShift = (uint_least8_t) (uint16_t) ADC_INTSELxNy_NUMBITS_PER_REG - ...'. Ta – Toby

+1

@Toby Oops 네, 그 부분을 놓쳤습니다. 게시물을 편집하겠습니다. 실제로 ADC_INTSELxNy_NUMBITS_PER_REG가 아닌 한 명시 적 캐스트가 필요합니다. 이미 충분히 큰 유형. – Lundin