sourcecode

왜 이것이 정의되지 않은 동작입니까?

copyscript 2022. 11. 6. 13:37
반응형

왜 이것이 정의되지 않은 동작입니까?

질문에 대한 의 대답은 다음과 같습니다.

inline bool divisible15(unsigned int x) 
{
    //286331153 = (2^32 - 1) / 15
    //4008636143 = (2^32) - 286331153
    return x * 4008636143 <= 286331153;
}

VS2008 컴파일러를 사용하는 머신에서는 완벽하게 동작했지만 여기서는 전혀 동작하지 않습니다.

컴파일러마다 다른 결과가 나오는 이유를 아시는 분? unsignedoverflow는 정의되지 않은 동작이 아닙니다.

주의: 테스트 결과, 나눗셈의 나머지를 15까지 취득하는 것보다 빠른 것이 확인되었습니다(단, 모든 컴파일러에서는 제외).

정의되지 않은 동작은 아닙니다.C89와 C99 사이의 C 언어 표준이 바뀌었을 뿐입니다.

C89에서, 4008636143과 같은 정수 상수는 다음과 같습니다.int또는long int하지만 꼭 들어맞는다.unsigned int서명되지 않았지만 C99에서는 다음 중 하나입니다.long int또는long long int(값을 유지할 수 있는 최소 크기에 따라 다름)그 결과 모든 표현은 64비트를 사용하여 평가되므로 오답이 발생합니다.

Visual Studio는 C89 컴파일러이므로 C89 동작이 발생하지만 이 IDEONE 링크는 C99 모드로 컴파일 중입니다.

이는 GCC를 사용하여 컴파일하면 더욱 명확해집니다.-Wall:

test.c: In function ‘divisible15’:
test.c:8:3: warning: this decimal constant is unsigned only in ISO C90

C89 3 3.1.3.2부터:

정수 상수의 유형은 해당 값을 나타낼 수 있는 목록의 첫 번째 유형입니다.고정되지 않은 10진수: int, long int, 부호 없는 long int, 고정되지 않은 8진수 또는 16진수: int, 부호 없는 int, 부호 없는 long int; [...

C99 § 6.4.4.1/5-6:

5) 정수 상수의 유형은 해당 정수 상수의 값을 나타낼 수 있는 목록의 첫 번째 유형이다.

Suffix | Decimal Constant | Octal or Hexadecimal Constant
-------+------------------+------------------------------
none   | int              | int
       | long int         | unsigned int
       | long long int    | long int
       |                  | unsigned long int
       |                  | long long int
       |                  | unsigned long long int
-------+------------------+------------------------------
[...]

6) 정수형이 목록 중 어떤 형식으로도 나타낼 수 없는 경우에는 확장 정수형이 그 값을 나타낼 수 있는 경우에는 확장 정수형을 가질 수 있다.상수 목록에 있는 모든 유형이 서명된 경우 확장 정수 유형이 서명됩니다. [...]

완전성을 위해 C++03은 정수 정수가 너무 커서 C+03에 맞지 않는 경우 실제로 정의되지 않은 동작을 가집니다.long intC++03 § 2.13.1/2부터:

정수 리터럴의 유형은 형식, 값 및 접미사에 따라 달라집니다.10진수이며 접미사가 없는 경우 값을 나타낼 수 있는 첫 번째 유형은 다음과 같습니다.int,long int; 값을 a로 나타낼 수 없는 경우long int동작은 정의되어 있지 않습니다.10월 16진수이고 접미사가 없는 경우, 이 값은 μ μ μ μ μ μ μ μ μ μ μ μ μ μ μ μ μint, , ,unsigned int, , ,long int, , ,unsigned long int. . [...]. [...]

C++11 의 동작은, C99 와 같습니다.C++11 의 2.14.2/3 를 참조해 주세요.

c89, C+03 정, C+03 μ+3 μ μ μ μ μ μ μ μ μ μ μ μ μ μ μu as ~하듯이4008636143u....

Since you are using 사용하고 계시기 때문에int상수, 컴파일러는 "사용" 오버플로이 정의되지 않을 수 있습니다.상수, 컴파일러는 코드를 단축하기 위해 정의되지 않은 오버플로를 "사용"할 수 있습니다.아래의 U를 수정하면 "작업"입니다.아래와 같이 U로 수정하면 "작동"합니다.

inline bool divisible15(unsigned int x) 
{
    //286331153 = (2^32 - 1) / 15
    //4008636143 = (2^32) - 286331153
    return x * 4008636143u <= 286331153u;
}

테스트 대상:

#include <iostream>


inline bool divisible15a(unsigned int x) 
{
    //286331153 = (2^32 - 1) / 15
    //4008636143 = (2^32) - 286331153
//    return x * 4008636143 <= 286331153;
    return x * 4008636143u <= 286331153;
}

inline bool divisible15b(unsigned int x) 
{
    //286331153 = (2^32 - 1) / 15
    //4008636143 = (2^32) - 286331153
//    return x * 4008636143 <= 286331153;
    return x * 4008636143 <= 286331153;
}


int main()
{
    for(unsigned int i = 0; i < 100; i++)
    {
    if (divisible15a(i))
    {
        std::cout << "a:" << i << std::endl;
    }
    if (divisible15b(i))
    {
        std::cout << "b:" << i << std::endl;
    }
    }
}

출력:

a:0
b:0
a:15
a:30
a:45
a:60
a:75
a:90

코드:

_Z12divisible15aj:
.LFB1192:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    %edi, -4(%rbp)
    movl    -4(%rbp), %eax
    imull   $-286331153, %eax, %eax
    cmpl    $286331153, %eax
    setbe   %al
    popq    %rbp
    ret

_Z12divisible15bj:
.LFB1193:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    %edi, -4(%rbp)
    movl    -4(%rbp), %edx
    movl    $4008636143, %eax
    imulq   %rdx, %rax
    cmpq    $286331153, %rax
    setle   %al
    popq    %rbp
    ret

네, 칼/ 아담의 분석을 통해 32비트에서 맞지 않는 칼/ 에 ,에비 promoted, to 32/ so,adam않 with that in a i, therefore- yes는네의 so맞지' agree int 따라서 다음과 같이 승격됩니다.long ★★★★★★★★★★★★★★★★★」long long

언급URL : https://stackoverflow.com/questions/18706859/why-is-this-an-undefined-behavior

반응형