development

const-correctness는 컴파일러에게 최적화를위한 더 많은 공간을 제공합니까?

big-blog 2020. 10. 17. 11:39
반응형

const-correctness는 컴파일러에게 최적화를위한 더 많은 공간을 제공합니까?


가독성이 향상되고 프로그램이 오류 발생 가능성이 적다는 것을 알고 있지만 성능이 얼마나 향상됩니까?

참고로 참조와 const포인터 의 주요 차이점은 무엇입니까? 나는 그것들이 메모리에 다르게 저장되었다고 가정 할 것입니다. 그러나 어떻게 그렇게합니까?


[편집 :이 질문은 처음에 생각했던 것보다 더 미묘합니다.]

상수에 대한 포인터 또는 상수 참조를 선언하는 것은 컴파일러가 무엇이든 최적화하는 데 결코 도움이되지 않습니다. (이 답변 하단의 업데이트를 참조하십시오.)

const선언 선언 범위 내에서 식별자가 사용되는 방식만을 나타냅니다 . 기본 개체가 변경 될 수 없다고 말하지 않습니다.

예:

int foo(const int *p) {
    int x = *p;
    bar(x);
    x = *p;
    return x;
}

컴파일러는 (예) 전역 int에 대한 포인터가 될 수 있고 *p수정할 bar()있기 때문에 에 대한 호출에 의해 수정 되지 않는다고 가정 할 수 없습니다 .pbar()

컴파일러의 호출에 대해 충분히 알고있는 경우 foo()와의 내용 bar()이 입증 할 수있는 bar()수정하지 않습니다 *p, 그때 그것은 또한 const를 선언하지 않고 그 증거를 수행 할 수 있습니다 .

그러나 이것은 일반적으로 사실입니다. const선언 범위 내에서만 효과가 있기 때문에 컴파일러는 해당 범위 내에서 포인터 또는 참조를 처리하는 방법을 이미 볼 수 있습니다. 기본 개체를 수정하고 있지 않다는 것을 이미 알고 있습니다.

요컨대, const이 맥락에서하는 모든 일은 실수를 방지하는 것입니다. 컴파일러에게 아직 알지 못하는 것을 알려주지 않으므로 최적화와 관련이 없습니다.

호출하는 함수는 foo()어떻습니까? 처럼:

int x = 37;
foo(&x);
printf("%d\n", x);

컴파일러는이 인쇄 (37), 이후는 것을 증명할 수 foo()소요 const int *?

아니요. 상수에 foo()대한 포인터를 사용 하더라도 const-ness를 캐스트하고 int를 수정할 수 있습니다. (이것은 정의 되지 않은 동작 아닙니다 .) 여기서도 컴파일러는 일반적인 가정을 할 수 없습니다. foo()이러한 최적화를 수행 할만큼 충분히 알고 있다면 const.

const최적화를 허용 할 수 있는 유일한 시간 은 다음과 같은 경우입니다.

const int x = 37;
foo(&x);
printf("%d\n", x);

여기에서 x모든 메커니즘을 통해 수정 (예 : 포인터를 가져와 캐스트 제거 const)하는 것은 정의되지 않은 동작을 호출하는 것입니다. 따라서 컴파일러는 그렇게하지 않는다고 가정 할 수 있으며 상수 37을 printf ()로 전파 할 수 있습니다. 이러한 종류의 최적화는 선언하는 모든 개체에 대해 합법적입니다 const. (실제로는 절대로 참조하지 않는 지역 변수는 컴파일러가 범위 내에서 수정 여부를 이미 볼 수 있기 때문에 도움이되지 않습니다.)

"사이드 노트"질문에 답하려면, (a) const 포인터는 포인터입니다. (b) const 포인터는 NULL과 같을 수 있습니다. 내부 표현 (예 : 주소)이 동일 할 가능성이 높다는 것이 맞습니다.

[최신 정보]

으로 크리스토프는 의견에서 지적은 언급하지 않기 때문에, 내 대답은 불완전하다 restrict.

C99 표준의 섹션 6.7.3.1 (4)은 다음과 같이 말합니다.

B를 실행할 때마다 L을 P를 기반으로하는 & L이있는 lvalue라고합니다. L이 지정하는 객체 X의 값에 액세스하는 데 사용되고 X도 어떤 방식 으로든 수정되는 경우 다음 요구 사항이 적용됩니다. : T는 const 한정되지 않습니다. ...

(여기서 B는 T에 대한 제한 포인터 인 P가 범위 내에있는 기본 블록입니다.)

따라서 C 함수 foo()가 다음과 같이 선언되면 :

foo(const int * restrict p)

... 그런 다음 컴파일러 *p 수명 p동안 (즉, 실행 중에) 수정이 발생 하지 않는다고 가정 foo()할 수 있습니다. 그렇지 않으면 동작이 정의되지 않기 때문입니다.

따라서 원칙적으로 상수 restrict에 대한 포인터와 결합 하면 위에서 무시한 두 최적화를 모두 사용할 수 있습니다. 실제로 이러한 최적화를 구현하는 컴파일러가 있습니까? (적어도 GCC 4.5.2는 그렇지 않습니다.)

하는 것으로 restrict만 C가 아니라 C ++에 존재하는 (심지어 C + +0), 컴파일러 특정 확장자 제외하고.


constC ++ 에는 두 가지 문제가 있습니다 (최적화에 관한 한) :

  • const_cast
  • mutable

const_cast 즉, const 참조 또는 const 포인터로 객체를 전달하더라도 함수는 const-ness를 버리고 객체를 수정할 수 있습니다 (객체가 const가 아닌 경우 허용됨).

mutable mean that even though an object is const, some of its parts may be modified (caching behavior). Also, objects pointed to (instead of being owned) can be modified in const methods, even when they logically are part of the object state. And finally global variables can be modified too...

const is here to help the developer catch logical mistakes early.


Off the top of my head, I can think of two cases where proper const-qualification allows additional optimizations (in cases where whole-program analysis is unavailable):

const int foo = 42;
bar(&foo);
printf("%i", foo);

Here, the compiler knows to print 42 without having to examine the body of bar() (which might not be visible in the curent translation unit) because all modifications to foo are illegal (this is the same as Nemo's example).

However, this is also possible without marking foo as const by declaring bar() as

extern void bar(const int *restrict p);

In many cases, the programmer actually wants restrict-qualified pointers-to-const and not plain pointers-to-const as function parameters, as only the former make any guarantees about the mutability of the pointed-to objects.

As to the second part of your question: For all practical purposes, a C++ reference can be thought of as a constant pointer (not a pointer to a constant value!) with automatic indirection - it is not any 'safer' or 'faster' than a pointer, just more convenient.


const-correctness generally doesn't help performance; most compilers don't even bother to track constness beyond the frontend. Marking variables as const can help, depending on the situation.

References and pointers are stored exactly the same way in memory.


This really depends on the compiler/platform (it may help optimisation on some compiler that has not yet been written, or on some platform that you never use). The C and C++ standards say nothing about performance other than giving complexity requirements for some functions.

Pointers and references to const usually do not help optimisation, as the const qualification can legally be cast away in some situations, and it is possible that the object can be modified by a different non-const reference. On the other hand, declaring an object to be const can be helpful, as it guarantees that the object cannot be modified (even when passed to functions that the compiler does not know the definition of). This allows the compiler to store the const object in read-only memory, or cache its value in a centralised place, reducing the need for copies and checks for modifications.

Pointers and references are usually implemented in the exact same way, but again this is totally platform dependant. If you are really interested then you should look at the generated machine code for your platform and compiler in your program (if indeed you are using a compiler that generates machine code).


One thing is, if you declare a global variable const, it may be possible to put it in the read-only portion of a library or executable and thus share it among multiple processes with a read-only mmap. This can be a big memory win on Linux at least if you have a lot of data declared in global variables.

Another situation, if you declare a constant global integer, or float or enum, the compiler may be able to just put the constant inline rather than using a variable reference. That's a bit faster I believe though I'm not a compiler expert.

References are just pointers underneath, implementation-wise.


It can help performance a little bit, but only if you are accessing the object directly through its declaration. Reference parameters and such cannot be optimized, since there might be other paths to an object not originally declared const, and the compiler generally can't tell if the object you are referencing was actually declared const or not unless that's the declaration you are using.

If you are using a const declaration, the compiler will know that externally-compiled function bodies, etc. cannot modify it, so you get a benefit there. And of course things like const int's are propagated at compile time, so that's a huge win (compared to just an int).

References and pointers are stored exactly the same, they just behave differently syntactically. References are basically renamings, and so are relatively safe, whereas pointers can point to lots of different things, and are thus more powerful and error-prone.

I guess the const pointer would be architecturally identical to the reference, so the machine code and efficiency would be the same. the real difference is syntax -- references are a cleaner, easier to read syntax, and since you don't need the extra machinery provided by a pointer, a reference would be stylistically preferred.

참고URL : https://stackoverflow.com/questions/6313730/does-const-correctness-give-the-compiler-more-room-for-optimization

반응형