우리는 리눅스 커널 안에 코드를 작성하고 있기 때문에 리눅스 커널 코드에서 작동하는 PC-Lint/Flexelint를 얻을 수 없었습니다. 너무 많은 내장 기호 등. 그러나 그것은 부작용입니다.컴파일러 경고를 사용하여 상수 1 왼쪽 시프트 오버플로 잡기?
우리는 gcc로 시작하는 컴파일러가 몇 가지 있지만 다른 것들도 있습니다. 그들의 경고 옵션은 시간이 지남에 따라 점점 강해지고 있으며, 정적 분석 도구 역시 강력합니다.
내가 알고 싶은 것은 다음과 같습니다. 그렇습니다. "no magic numbers"와 같은 코드 리뷰에서 쉽게 잡을 수있는 몇 가지 사항을 위반하고 "비트 시프트에주의하십시오."하지만 코드의 해당 부분을 살펴보아야 만합니다. 어쨌든, 여기있다 :
unsigned long long foo;
unsigned long bar;
[... lots of other code ...]
foo = ~(foo + (1<<bar));
또한 업데이트] 문제 설명 -도 16로 제한 바, 여전히 문제. 명확히하자면, 문제는 암시 적 int 유형의 상수로, 계획되지 않은 경우 복잡한 계산식이 모든 계산이 동일한 크기와 부호로 수행된다는 규칙을 위반하게 만듭니다.
문제점 : '1'은 길지 않지만 작은 값 상수는 기본값이 int입니다. 그러므로 막대의 실제 값이 16을 초과하지 않더라도 여전히 (1<<bar)
표현이 오버플로되어 전체 계산이 망가질 수 있습니다.
아마도 올바른 해결책으로 대신 1ULL을 작성하십시오.
이 (수정 된) 문제점을 지적하는 잘 알려진 컴파일러 및 컴파일러 경고 플래그가 있습니까?
막대의 길이가 너무 크면 이동이 정의되지 않습니다 (제 생각에는 다소 불량합니다). 당신은 변수를 두 번째 피연산자에 대한 int로 이동 경고에 대한 컴파일러를 요구하는 것 같습니다. 그러나 문제는 '1'이 길지 않다는 것입니다. 오랫동안 변수 이동에 대해 경고하고 싶지 않습니까? 필자는 컴파일러 작성자가 경고가 유용 할 것으로 기대하는 이유를 알지 못하고 <<에 대한 가변적 인 두 번째 피연산자에 대한 일반적인 경고로 인해 엄청난 양의 오 탐지가 발생합니다. –
@onebyone :'int'가 32 비트이고'long long'이 64라고 가정하면'~ (foo + (1 << bar))'는'0 <= bar <32'에 대해서만 작동하며'~ (foo + (1LL << bar))'는'0 <= bar <64'에서 작동합니다. 나는 전자가 후자 대신에 쓸 때 OP가 경고를 원한다고 생각한다. – ephemient
물론, foo가 int이고 bar가 논리적으로 (유형이 아닌) 1 또는 2로 제한되는 경우 경고를 원하겠습니까? foo가 긴 long이고 bar가 1 또는 2 인 곳은 어떨까요? 오버플로 결과가 정의되지 않았으므로 부호있는 상수에 막대를 곱하거나 추가하는 경고?컴파일러는 대개 논리적 제약 조건을 식별 할 수 없으므로 이러한 경고가 오 탐지 가능성이 높습니다. 나쁜 아이디어라는 것을 의미하지는 않습니다. 필자는 왜 이것이 무엇이되어야하는지 정의하기가 어렵고 어쨌든 컴파일러 작성자에게는 우선 순위가 낮다고 추측합니다. –