warning - char 및 unsigned char을 비교할 때 컴파일러 경고를 사용하는 방법?




make no warnings (3)

i signed char 이기 때문에 그 값의 범위는 일반적으로 -128 to 127 입니다. unsigned char count 에는 255 (0xFF) 값이 할당됩니다.

루프 내에서 i 값이 127 되고 다시 증가하면 128 도달하지 않고 -128 되고 다시 127 되고 다시 -128 롤오버됩니다. i 의 값은 루프 내부의 count 값보다 영원히 작을 것이므로 루프를 종료 할 수 없습니다!

이는 데이터 유형의 오버플로 때문에 발생하며 경고를 내지 않으므로 자동 유형 강제 변환이 발생할 수있는 표현을 비판적으로 조사해야합니다.

편집 : GCC 문서에서,

-Wconversion : 값을 변경할 수있는 암시 적 변환에 대해 경고합니다.

여기서는 비교가 아닌 할당으로 인해 일관성이 없습니다.

예를 들어 다음 C 코드를 가져옵니다.

int main(int argc, char *argv[])
{
    signed char i;
    unsigned char count = 0xFF;

    for (i=0; i<count;i++)
    {
        printf("%x\n", i);
    }
    return 0;
}

이 코드는 다음과 같이 컴파일하더라도 무한 루프에서 실행됩니다.

# gcc -Wall -Wpedantic -Wconversion -Wsign-compare -Wtype-limits -Wsign-conversion test.c -o test

누군가 그런 종류의 문제에 대해 경고해야하는 컴파일러 플래그를 알고 있습니까?

그냥 명확히하기 위해, 나는 왜 '무한 루프가 생기는가'를 묻는 것이 아니라, 컴파일러 나 정적 분석을 사용하지 못하게하는 방법이 있는지 알고 싶습니다.


i signed char 이며, SCHAR_MAX 를 넘어서 증가 시키면 구현 정의 효과가있다. 계산 i + 1i 에서 int 승격 된 후에 수행되며 sizeof(int) == 1SCHAR_MAX == INT_MAX 가 아닌 한 오버플로하지 않습니다. 그러나이 값은 i 의 범위를 벗어나며 i 는 부호가있는 유형이므로 결과가 구현 정의이거나 구현 정의 신호가 발생합니다. (C11 6.3.1.3p3 부호있는 및 부호없는 정수).

정의에 따르면, 컴파일러는 구현이므로 특정 시스템 및 x86 아키텍처에서 동작을 정의하면 값을 저장하면 하위 비트를 마스킹합니다. gcc 는 루프 테스트가 확실히 일정하다는 점을 알고 있어야합니다. 무한 루프.

clang 은 상수 테스트도 감지하지 못하지만 clang 3.9.0countconst 로 선언되면 gcc 와 달리 i < counti < 0xff 로 바뀌면 경고를 발행합니다.

두 피연산자가 실제로 비교하기 전에 int 승격되기 때문에 컴파일러는 서명 / 서명되지 않은 비교 문제에 대해 불평하지 않습니다.

여기에서 의미있는 문제를 발견했습니다. 특히 중요한 것은 일부 코딩 규칙이 모든 변수에 대해 가능한 가장 작은 유형을 사용하여 int8_t 또는 uint8_t 루프 인덱스 변수와 같은 기이함을 int8_t 입니다. 이러한 선택은 실제로 오류가 발생하기 쉽고 컴파일러에서 프로그래머에게 게시 한 바보 같은 오류에 대해 경고하는 방법을 찾지 못했습니다.


이 코드를 컴파일러의 관점에서 의심 할 여지가 없기 때문에 이것을 잡을 경고는 없습니다.

  1. 다른 답변에서 지적한 것처럼 비교 라인은 다음과 같이 효과적으로 처리됩니다.

    for (i=0; (int)i<(int)count; i++)
    • 국제 표준 프로그래밍 언어 - C , 6.3.1.1 절에 설명 된 것처럼 예상치 못한 비교 결과에 대한 가능성이 적기 때문에 값을 비교할 때 암시 적 유형 변환을위한 "값 보존"방식을 선택했습니다.

      • 산술 비교 결과 가 예상 결과 이므로 프로그램이 "잘못"실행됩니다 .
    • 이것이 int 경우 int 는 원칙적으로 하드웨어 유형 (또는 적어도 C가이를 염두에두고 설계 되었기 때문에)을 구현하는 것은 불가능합니다. 한 피연산자가 서명되고 다른 피연산자는 서명되지 않는 아키텍처 이것은 char 여기에서 int 대체하면 컴파일러가 "signed and unsigned 비교"경고를 발행하는 핵심 이유입니다 .

  2. 증가 연산의 경우, i++ ,

    • 동일한 위의 연계 된 이론적 근거는 몇몇 장소에서 "침묵의 넘침"이 가장 보편적이고 기대되는 의미론이라고 언급한다. 그것은 심지어 "C 커뮤니티의 민감성이 부족하여 부호가있는 연산과 부호가없는 연산의 차이"가 발생했다고 설명했습니다. 그래서 여기도 의심의 여지가 없습니다.

궁극적으로,이 혼란을 야기한 것은 int 프로모션 의미론에 대한 당신의 욕구입니다. 그 때문에 코드의 동작이 예상치 못한 결과를 낳았습니다 (나쁘지는 않습니다. 다른 답변을 읽기 전에이 사실을 알지 못했습니다!). 그러나 표준에 대한 기대는 매우 높습니다. "법에 대한 무지는 변명의 여지가 없다"고 그들은 말한다.





signed