C ++에서 제한 키워드는 무엇을 의미합니까?
나는 항상 확실하지 않았다. C ++에서 restrict 키워드는 무엇을 의미 하는가?
함수에 주어진 둘 이상의 포인터가 겹치지 않는다는 것을 의미합니까? 그게 무슨 뜻입니까?
Christer Ericson은 자신의 논문 인 Memory Optimization 에서 restrict
아직 C ++ 표준의 일부는 아니지만 많은 컴파일러에서 지원하고 있으며 가능한 경우 사용을 권장한다고 말합니다.
키워드 제한
! 1999 ANSI / ISO C 표준에 새로 추가
! C ++ 표준은 아니지만 많은 C ++ 컴파일러에서 지원
! 힌트 만이므로 아무 것도 할 수 없으며 여전히 준수하고 있습니다.
제한 규정 포인터 (또는 참조) ...
! ... 기본적으로 컴파일러는 포인터의 범위에 대해 포인터의 대상이 해당 포인터를 통해 액세스 할 수 있습니다 (포인터에서 복사 된 포인터).
이를 지원하는 C ++ 컴파일러에서는 아마도 C에서와 동일하게 작동해야합니다.
자세한 내용은이 SO 게시물을 참조하십시오 : C99 '제한'키워드의 현실적인 사용법?
에릭슨의 논문을 훑어 보려면 30 분이 걸립니다. 재미 있고 가치가 있습니다.
편집하다
또한 IBM의 AIX C / C ++ 컴파일러가 __restrict__
keyword 키워드를 지원 한다는 것을 알았습니다 .
g ++은 다음 프로그램이 g ++에서 깔끔하게 컴파일되므로 이것을 지원하는 것 같습니다.
#include <stdio.h>
int foo(int * __restrict__ a, int * __restrict__ b) {
return *a + *b;
}
int main(void) {
int a = 1, b = 1, c;
c = foo(&a, &b);
printf("c == %d\n", c);
return 0;
}
나는 또한 사용에 관한 좋은 기사를 발견했다 restrict
.
편집 2
C ++ 프로그램에서 제한 사용에 대해 구체적으로 설명하는 기사를 살펴 보았습니다.
또한 Microsoft Visual C ++ 는 __restrict
키워드를 지원합니다 .
다른 사람들이 말했듯이, C ++ 14의 의미가 없다면__restrict__
C99와 동일한 GCC 확장을 고려하십시오 restrict
.
C99
restrict
두 포인터가 겹치는 메모리 영역을 가리킬 수 없다고 말합니다. 가장 일반적인 사용법은 함수 인수입니다.
이것은 함수 호출 방법을 제한하지만 더 많은 컴파일 최적화를 허용합니다.
발신자가 restrict
계약을 따르지 않으면 정의되지 않은 동작입니다.
C99 N1256 초안 6.7.3 / 7 "형식 한정자"말한다 :
제한 규정 자 (레지스터 저장 클래스와 같은)의 의도 된 사용은 최적화를 촉진하는 것이며, 규정을 준수하는 프로그램을 구성하는 모든 사전 처리 변환 단위에서 규정 자의 모든 인스턴스를 삭제해도 의미가 변경되지 않습니다 (즉, 관찰 가능한 동작).
그리고 6.7.3.1 "제한의 공식적 정의"는 세부 사항을 제공한다.
가능한 최적화
위키 백과의 예 입니다 매우 조명.
하나의 조립 명령을 저장할 수있는 방법을 명확하게 보여줍니다 .
제한없이 :
void f(int *a, int *b, int *x) {
*a += *x;
*b += *x;
}
의사 어셈블리 :
load R1 ← *x ; Load the value of x pointer
load R2 ← *a ; Load the value of a pointer
add R2 += R1 ; Perform Addition
set R2 → *a ; Update the value of a pointer
; Similarly for b, note that x is loaded twice,
; because a may be equal to x.
load R1 ← *x
load R2 ← *b
add R2 += R1
set R2 → *b
제한으로 :
void fr(int *__restrict__ a, int *__restrict__ b, int *__restrict__ x);
의사 어셈블리 :
load R1 ← *x
load R2 ← *a
add R2 += R1
set R2 → *a
; Note that x is not reloaded,
; because the compiler knows it is unchanged
; load R1 ← *x
load R2 ← *b
add R2 += R1
set R2 → *b
GCC가 실제로합니까?
g++
4.8 리눅스 x86-64 :
g++ -g -std=gnu++98 -O0 -c main.cpp
objdump -S main.o
로도 -O0
동일합니다.
로 -O3
:
void f(int *a, int *b, int *x) {
*a += *x;
0: 8b 02 mov (%rdx),%eax
2: 01 07 add %eax,(%rdi)
*b += *x;
4: 8b 02 mov (%rdx),%eax
6: 01 06 add %eax,(%rsi)
void fr(int *__restrict__ a, int *__restrict__ b, int *__restrict__ x) {
*a += *x;
10: 8b 02 mov (%rdx),%eax
12: 01 07 add %eax,(%rdi)
*b += *x;
14: 01 06 add %eax,(%rsi)
시작하지 않은 경우 호출 규칙 은 다음과 같습니다.
rdi
= 첫 번째 매개 변수rsi
= 두 번째 매개 변수rdx
= 세번째 매개 변수
GCC 출력은 Wiki 기사보다 훨씬 명확했습니다. 4 가지 명령어와 3 개의 명령어.
배열
So far we have single instruction savings, but if pointer represent arrays to be looped over, a common use case, then a bunch of instructions could be saved, as mentioned by supercat and michael.
Consider for example:
void f(char *restrict p1, char *restrict p2, size_t size) {
for (size_t i = 0; i < size; i++) {
p1[i] = 4;
p2[i] = 9;
}
}
Because of restrict
, a smart compiler (or human), could optimize that to:
memset(p1, 4, size);
memset(p2, 9, size);
Which is potentially much more efficient as it may be assembly optimized on a decent libc implementation (like glibc) Is it better to use std::memcpy() or std::copy() in terms to performance?, possibly with SIMD instructions.
Without, restrict, this optimization could not be done, e.g. consider:
char p1[4];
char *p2 = &p1[1];
f(p1, p2, 3);
Then for
version makes:
p1 == {4, 4, 4, 9}
while the memset
version makes:
p1 == {4, 9, 9, 9}
Does GCC really do it?
GCC 5.2.1.Linux x86-64 Ubuntu 15.10:
gcc -g -std=c99 -O0 -c main.c
objdump -dr main.o
With -O0
, both are the same.
With -O3
:
with restrict:
3f0: 48 85 d2 test %rdx,%rdx 3f3: 74 33 je 428 <fr+0x38> 3f5: 55 push %rbp 3f6: 53 push %rbx 3f7: 48 89 f5 mov %rsi,%rbp 3fa: be 04 00 00 00 mov $0x4,%esi 3ff: 48 89 d3 mov %rdx,%rbx 402: 48 83 ec 08 sub $0x8,%rsp 406: e8 00 00 00 00 callq 40b <fr+0x1b> 407: R_X86_64_PC32 memset-0x4 40b: 48 83 c4 08 add $0x8,%rsp 40f: 48 89 da mov %rbx,%rdx 412: 48 89 ef mov %rbp,%rdi 415: 5b pop %rbx 416: 5d pop %rbp 417: be 09 00 00 00 mov $0x9,%esi 41c: e9 00 00 00 00 jmpq 421 <fr+0x31> 41d: R_X86_64_PC32 memset-0x4 421: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 428: f3 c3 repz retq
Two
memset
calls as expected.without restrict: no stdlib calls, just a 16 iteration wide loop unrolling which I do not intend to reproduce here :-)
I haven't had the patience to benchmark them, but I believe that the restrict version will be faster.
Strict aliasing rule
The restrict
keyword only affects pointers of compatible types (e.g. two int*
) because the strict aliasing rules says that aliasing incompatible types is undefined behavior by default, and so compilers can assume it does not happen and optimize away.
See: What is the strict aliasing rule?
Does it work for references?
According to the GCC docs it does: https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Restricted-Pointers.html with syntax:
int &__restrict__ rref
There is even a version for this
of member functions:
void T::fn () __restrict__
Nothing. It was added to the C99 standard.
This is the original proposal to add this keyword. As dirkgently pointed out though, this is a C99 feature; it has nothing to do with C++.
There's no such keyword in C++. List of C++ keywords can be found in section 2.11/1 of C++ language standard. restrict
is a keyword in C99 version of C language and not in C++.
Since header files from some C libraries use the keyword, the C++ language will have to do something about it.. at the minimum, ignoring the keyword, so we don't have to #define the keyword to a blank macro to suppress the keyword.
참고URL : https://stackoverflow.com/questions/776283/what-does-the-restrict-keyword-mean-in-c
'IT' 카테고리의 다른 글
Conda가 virtualenv의 필요성을 대체합니까? (0) | 2020.05.20 |
---|---|
배열의 주소는 C의 값과 어떻게 다릅니 까? (0) | 2020.05.20 |
'setdefault'dict 메소드의 사용 사례 (0) | 2020.05.20 |
뒤로 버튼을 클릭 할 때 크로스 브라우저 onload 이벤트가 있습니까? (0) | 2020.05.20 |
this 포인터를 통해 템플릿 기본 클래스 멤버에 액세스해야하는 이유는 무엇입니까? (0) | 2020.05.20 |