programing

왜 C 컴파일러는 같은 변수에 대한 두 개의 포인터가 불법/UB일 것이라고 가정하고 const pointer의 값을 변경하는 것을 최적화할 수 없는가?

copyandpastes 2022. 8. 10. 23:25
반응형

왜 C 컴파일러는 같은 변수에 대한 두 개의 포인터가 불법/UB일 것이라고 가정하고 const pointer의 값을 변경하는 것을 최적화할 수 없는가?

최근 Rust와 C의 비교에 실패했는데, 다음 코드를 사용하고 있습니다.

bool f(int* a, const int* b) {
  *a = 2;
  int ret = *b;
  *a = 3;
  return ret != 0;
}

Rust(동일한 코드, 그러나 Rust 구문을 사용하는 경우)에서는 다음과 같은 어셈블러 코드가 생성됩니다.

    cmp      dword ptr [rsi], 0 
    mov      dword ptr [rdi], 3 
    setne al                    
    ret

gcc를 사용하면 다음과 같은 결과가 나타납니다.

   mov      DWORD PTR [rdi], 2   
   mov      eax, DWORD PTR [rsi]
   mov      DWORD PTR [rdi], 3        
   test     eax, eax                  
   setne al                           
   ret

텍스트는 C 함수가 첫 번째 줄의 위치를 최적화할 수 없다고 주장합니다.a그리고.b같은 번호를 가리킬 수 있습니다.Rust에서는 이것이 허용되지 않기 때문에 컴파일러는 이를 최적화하여 제거할 수 있습니다.

이제 질문 드리겠습니다.

이 함수는const int*const int에 대한 포인터입니다.질문을 읽었는데 포인터로 const int를 수정하면 컴파일러 경고와 UB에서 최악의 캐스트가 발생한다고 되어 있습니다.

같은 정수에 대한 포인터 2개로 호출하면 이 함수가 UB가 될 수 있습니까?

왜 C 컴파일러는 같은 변수에 대한 두 개의 포인터가 불법/UB일 것이라는 가정 하에 첫 번째 줄 떨어진 곳을 최적화할 수 없는가?

godbolt 링크

왜 C 컴파일러는 같은 변수에 대한 두 개의 포인터가 불법/UB일 것이라는 가정 하에 첫 번째 줄의 컴파일러를 최적화할 수 없는가?

C 컴파일러에 지시하지 않았기 때문에 C 컴파일러는 그러한 가정을 할 수 있습니다.

C에는 정확히 이 에 대한 유형 한정자가 있습니다.restrict즉, 이 포인터는 다른 포인터와 겹치지 않습니다(정확하지는 않지만 따라 재생합니다).

의 어셈블리 출력

bool f(int* restrict a, const int* b) {
  *a = 2;
  int ret = *b;
  *a = 3;
  return ret != 0;
}

        mov     eax, DWORD PTR [rsi]
        mov     DWORD PTR [rdi], 3
        test    eax, eax
        setne   al
        ret

...할당을삭제/삭제합니다.*a = 2

https://en.wikipedia.org/wiki/Restrict 에서

C 프로그래밍 언어에서 restrict는 포인터 선언에서 사용할 수 있는 키워드입니다.이 타입 한정자를 추가함으로써 프로그래머는 포인터의 수명 동안 포인터 자체 또는 포인터로부터 직접 파생된 값(예를 들어 포인터 + 1)만이 포인터가 가리키는 오브젝트에 액세스하기 위해 사용될 것임을 컴파일러에 암시합니다.

함수int f(int *a, const int *b);내용을 바꾸지 않겠다는 약속b 포인터를 통해...이 프로그램은 이 시스템을 통한 변수 접근에 대한 어떠한 약속도 하지 않습니다.a포인터

한다면a그리고.b같은 오브젝트를 포인트 하는 것은 합법입니다(기본 오브젝트를 변경할 수 있는 경우).

예:

int val = 0;
f(&val, &val);

다른 답변은 C쪽을 언급하고 있지만, Rust쪽을 살펴볼 필요가 있습니다.Rust를 사용하는 코드는 다음과 같습니다.

fn f(a:&mut i32, b:&i32)->bool{
    *a = 2;
    let ret = *b;
    *a = 3;
    return ret != 0;
}

이 함수는 두 개의 참조를 사용합니다. 하나는 가변이고 하나는 비변환입니다.참조는 읽기에 유효함을 보증하는 포인터이며, 가변 참조도 고유함을 보증하기 때문에 다음과 같이 최적화됩니다.

        cmp     dword ptr [rsi], 0
        mov     dword ptr [rdi], 3
        setne   al
        ret

그러나 Rust는 또한 C의 포인터와 동등한 원시 포인터를 가지고 있으며 그러한 보증을 하지 않습니다.다음 함수는 원시 포인터를 사용합니다.

unsafe fn g(a:*mut i32, b:*const i32)->bool{
    *a = 2;
    let ret = *b;
    *a = 3;
    return ret != 0;
}

는 최적화를 생략하고 다음과 같이 컴파일합니다.

        mov     dword ptr [rdi], 2
        cmp     dword ptr [rsi], 0
        mov     dword ptr [rdi], 3
        setne   al
        ret

고드볼트 링크

이 함수는const int*const int에 대한 포인터입니다.

아니요, const int에 대한 포인터가 아닙니다.그런 말을 하는 사람은 누구나 착각하고 있다.

  • int*확실히 일정하지 않은 int에 대한 포인터입니다.

  • const int*는 알 수 없는 항상성의 int에 대한 포인터입니다.

  • 확실히 일정한 int에 대한 포인터의 개념을 표현할 방법은 없습니다.

만약 C가 더 잘 디자인된 언어라면,const int *경찰서에 대한 포인터가 될 수 있습니다.mutable int *(키워드를 C++에서 차용)는 비정수 int로의 포인터가 됩니다.int *알 수 없는 항상성의 int에 대한 포인터가 될 수 있습니다.예선 탈락(즉, 포인트 투 타입에 대한 무언가를 잊어버리는 것)은 안전할 것입니다. 즉, 실제 C가 추가되는 과는 반대입니다.const한정자는 안전합니다.Rust를 사용한 적은 없습니다만, 다른 회답의 예에서는, 그러한 구문을 사용하고 있는 것 같습니다.

Bjarne Stroustrup, 는 다음과 같이 소개했습니다.const, 원래 이름은 이었습니다.readonly그것은 실제의 의미에 훨씬 더 가깝다. int readonly*포인터가 읽기 전용이라는 걸 분명히 했을 거야 가리키는 물체가 아니라로의 이름const프로그래머 세대들을 혼란스럽게 했습니다.

내가 선택할 수 있을 때, 나는 항상 글을 쓴다.foo const*,것은 아니다.const foo*차선책으로서readonly*.

이 질문에서는 다음 항목에 대한 최적화에 대해 설명한다는 점에 주의해 주십시오.-Ofast어떻게 그런지도 모르니까요

기본적으로 함수의 C 컴파일러는 여러 변환 유닛에서 함수를 호출할 수 있기 때문에 링크 타임/런타임이 될 때까지 전달될 수 있는 완전한 이산 주소 집합을 알지 못합니다.따라서 C 컴파일러는 다음과 같은 법적 주소를 처리하는 것을 고려합니다.a ★★★★★★★★★★★★★★★★★」b물론 두 가지가 겹치는 경우를 가리키기도 합니다.

때문에 이렇게 '아까', '아까', '아까', '아까', '아까'를 사용해야 합니다.restricta 때문에 상수에서 수 는 값을 하지 않습니다b 있습니다되어야 하기 에, 「0」에 격납되어 있습니다.이것은 0과의 비교에 포함할 필요가 있습니다.따라서 스토어는a이는 비교를 진행하기 전에 발생하지만 녹이 슬었을 경우 기본 가정은 제한적입니다. 이 는 이 함수에 알고 있습니다.*a is is is is is와 *(a+1-1) 스토어는 2개의 스토어는 .a ★★★★★★★★★★★★★★★★★」b

언급URL : https://stackoverflow.com/questions/65993616/why-cant-the-c-compiler-optimize-changing-the-value-of-a-const-pointer-assuming

반응형