차이점은 무엇입니까
int x=7;
과
register int x=7;
?
C ++를 사용하고 있습니다.
차이점은 무엇입니까
int x=7;
과
register int x=7;
?
C ++를 사용하고 있습니다.
register는 C와 C ++간에 서로 다른 의미를 갖습니다.
register int a[1];할 수 있습니다.이 선언을 사용하면 해당 배열을 인덱싱 할 수 없습니다. 시도하면 UB
답변:
2010 년에 존재했던 C ++에서 "auto"또는 "register"키워드를 사용하는 유효한 프로그램은 해당 키워드가 제거 된 프로그램과 의미 상 동일합니다 (문자열 매크로 또는 기타 유사한 컨텍스트에 나타나지 않는 한). 그런 의미에서 키워드는 프로그램을 적절하게 컴파일하는 데 쓸모가 없습니다. 반면에 키워드는 특정 매크로 컨텍스트에서 매크로를 잘못 사용하면 가짜 코드를 생성하는 대신 컴파일 타임 오류가 발생하도록하는 데 유용 할 수 있습니다.
C ++ 11 및 이후 버전의 언어에서 auto키워드는 초기화 된 객체에 대한 의사 유형으로 작동하도록 용도가 변경되었으며 컴파일러는이를 초기화 표현식의 유형으로 자동으로 대체합니다. 따라서 C ++ 03에서 선언 : auto int i=(unsigned char)5;은 int i=5;블록 컨텍스트 내에서 사용될 때 와 동일 auto i=(unsigned char)5;하며 제약 조건 위반이었습니다. C ++ 11에서는 auto int i=(unsigned char)5;제약 조건 위반 auto i=(unsigned char)5;이되었고 auto unsigned char i=5;.
auto를 간단히 생략 할 수 없습니다 ... 답변을 업데이트 할 수 있습니다.
register은 더 이상 사용되지 않으며 C ++ 17에서 제거 할 제안이있을 것입니다.
auto은 이제 자동 유형 추론에 사용되지만 그 전에는 변수가 "자동"으로 저장되도록 지정하는 데 사용되었습니다 ( 따라서 스택 에서) 키워드 register( "프로세서의 레지스터"를 의미 )와는 반대로 :
register 메모리 대신 프로세서 레지스터에 해당 변수를 저장하도록 권고하는 컴파일러에 대한 힌트입니다 (예 : 스택 대신).
컴파일러는 그 힌트를 따를 수도 있고 따르지 않을 수도 있습니다.
Herb Sutter에 따르면 "아닌 키워드 (또는 다른 이름의 주석)" :
레지스터 지정자는 자동 지정자와 동일한 의미를 갖습니다.
storage-class-specifier문법의 하나 가 아니며 정의 된 의미가 없습니다. 준수 컴파일러는 Clang과 같은 오류를 발생시킬 수 있습니다. 그럼에도 불구하고 일부 구현에서는 여전히이를 허용하고 무시 (MSVC, ICC)하거나 최적화 힌트 (GCC)로 사용합니다. open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0001r1.html을 참조하십시오 . 하지만 한 가지 요점을 잘못 언급했습니다. C ++ 11에서는 더 이상 사용되지 않습니다.
에 따르면 허브 셔터 , register"입니다 공백과 정확히 같은 의미 "와 C ++ 프로그램의 의미에 영향을주지 않습니다.
registerC ++ 11에서는 더 이상 사용되지 않습니다. C ++ 17에서는 사용되지 않고 예약되어 있습니다.
register키워드는 유용했다 :
register키워드가 필요한 생산 시스템의 예 :
typedef unsigned long long Out;
volatile Out out,tmp;
Out register rax asm("rax");
asm volatile("rdtsc":"=A"(rax));
out=out*tmp+rax;
C ++ 11 이후로 더 이상 사용되지 않으며 사용되지 않으며 C ++ 17 에서 예약되어 있습니다.
register스토리지 클래스 지정자와 다르며 GCC에서 계속 지원합니다.
GCC 9.3로, 사용하여 컴파일 -std=c++2a, register 컴파일러 경고를 생산,하지만 여전히 C의 동일 원하는 효과 및 동작합니다있다 register-O1없이 컴파일 할 때 - Ofast 최적화 플래그의 측면에서 이 대답. 그러나 clang ++-7을 사용하면 컴파일러 오류가 발생합니다. 예, register최적화는 최적화 -O 플래그가없는 표준 컴파일에서만 차이를 만들지 만 컴파일러가 -O1으로도 알아낼 수있는 기본 최적화입니다.
유일한 차이점은 C ++에서 레지스터 변수의 주소를 사용할 수 있다는 것입니다. 즉, 변수 또는 별칭의 주소 (포인터 생성)를 사용하지 않거나 참조를 사용하지 않는 경우에만 최적화가 발생합니다. 단지의 코드 (에서 그것의 - O0 때문에 참조 또한, 주소를 가지고 있기 때문에 그것이 스택에 const를 포인터의 그들이 것을 제외하고 -Ofast를 사용하여 컴파일하는 경우 포인터처럼 스택에서 최적화 할 수 있습니다,,, 결코 나타나지 않습니다 -Ofast를 사용하여 스택에서 포인터와 달리 만들 volatile수없고 주소를 가져올 수 없기 때문입니다. 그렇지 않으면 사용하지 않은 것처럼 동작 register하고 값이 스택에 저장됩니다.
-O0에서 또 다른 차이점은 const registergcc C와 gcc C ++에서 동일하게 작동하지 않는다는 것입니다. gcc C에서는 block-scope 가 gcc에서 최적화되지 않았기 때문에 const register처럼 동작 합니다. clang C 에서는 아무것도하지 않으며 블록 범위 최적화 만 적용됩니다. gcc C에서는 최적화가 적용되지만 블록 범위에서는 최적화가 없습니다. gcc C ++에서는 두 최적화 와 블록 범위 최적화가 결합됩니다.registerconstregisterconstregisterconstregisterconst
#include <stdio.h> //yes it's C code on C++
int main(void) {
const register int i = 3;
printf("%d", i);
return 0;
}
int i = 3;:
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 3
mov eax, DWORD PTR [rbp-4]
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
register int i = 3;:
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
push rbx
sub rsp, 8
mov ebx, 3
mov esi, ebx
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
mov rbx, QWORD PTR [rbp-8] //callee restoration
leave
ret
const int i = 3;
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 3 //still saves to stack
mov esi, 3 //immediate substitution
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
const register int i = 3;
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
mov esi, 3 //loads straight into esi saving rbx push/pop and extra indirection (because C++ block-scope const is always substituted immediately into the instruction)
mov edi, OFFSET FLAT:.LC0 // can't optimise away because printf only takes const char*
mov eax, 0 //zeroed: https://stackoverflow.com/a/6212755/7194773
call printf
mov eax, 0 //default return value of main is 0
pop rbp //nothing else pushed to stack -- more efficient than leave (rsp == rbp already)
ret
register컴파일러에게 1) 피 호출자 저장 레지스터에 지역 변수를 저장하고,이 경우 rbx2) 변수의 주소를 가져 오지 않으면 스택 쓰기를 최적화하도록 지시 합니다. const컴파일러에게 값을 레지스터에 할당하거나 메모리에서로드하는 대신 즉시 값 을 대체 하고 로컬 변수를 기본 동작으로 스택에 쓰도록 지시합니다. const register이러한 대담한 최적화의 조합입니다. 이것은 얻는 것만 큼 슬림합니다.
또한 gcc C 및 C ++에서 register자체적으로 스택의 첫 번째 로컬에 대해 스택에 임의의 16 바이트 간격 을 만드는 것처럼 보이지만 const register.
그러나 -Ofast를 사용하여 컴파일; register0 최적화 효과가 있습니다. 왜냐하면 레지스터에 넣을 수 있거나 즉시 만들 수 있다면 항상 그렇고 그렇지 않으면 그렇지 않을 것입니다. const여전히 C 및 C ++의로드를 최적화하지만 파일 범위에서만 ; volatile여전히 값이 스택에서 저장되고로드되도록 강제합니다.
.LC0:
.string "%d"
main:
//optimises out push and change of rbp
sub rsp, 8 //https://stackoverflow.com/a/40344912/7194773
mov esi, 3
mov edi, OFFSET FLAT:.LC0
xor eax, eax //xor 2 bytes vs 5 for mov eax, 0
call printf
xor eax, eax
add rsp, 8
ret
컴파일러의 옵티 마이저에 두 개의 변수가 있고 하나를 스택에 넘겨야하는 경우를 고려하십시오. 두 변수가 컴파일러에 대해 동일한 가중치를 갖게되었습니다. 차이가 없다면 컴파일러는 변수 중 하나를 임의로 유출합니다. 반면에 register키워드는 컴파일러에게 어떤 변수가 더 자주 액세스되는지 힌트를 제공합니다. x86 프리 페치 명령어와 유사하지만 컴파일러 최적화 프로그램 용입니다.
분명히 register힌트는 사용자가 제공 한 분기 확률 힌트와 유사하며 이러한 확률 힌트에서 추론 할 수 있습니다. 컴파일러가 일부 분기가 자주 사용된다는 것을 알고 있으면 분기 관련 변수를 레지스터에 유지합니다. 그래서 나는 분기 힌트에 대해 더 신경을 쓰고 register. 이상적으로는 프로파일 러가 어떻게 든 컴파일러와 통신하고 그러한 뉘앙스에 대해 생각하지 않아도됩니다.