programing

"register" 키워드는 C에 있나요?

randomtip 2022. 7. 21. 22:04
반응형

"register" 키워드는 C에 있나요?

「 」가 죠?register워는는는 언언언?최적화에 사용되고 있다고 읽었지만, 어느 표준에도 명확하게 정의되어 있지 않습니다.직직관 련련? 면면면 면면 면면 ?? 면? 면? ??

컴파일러에 대한 힌트는 변수가 많이 사용되고 가능하면 프로세서 레지스터에 저장할 것을 권장합니다.

대부분의 현대 컴파일러는 자동으로 컴파일러를 선택하고 있으며, 우리 인간보다 더 잘 고릅니다.

컴파일러가 레지스터가 아닌 메모리에 변수를 유지하기로 결정했다고 해도 레지스터 변수의 주소를 받을 수 없다는 것을 아무도 언급하지 않은 것이 놀랍습니다.

이렇게 쓰면서register합니다), 져 버립니다(컴파일러는 변수를 어디에 둘지 결정합니다).&연산자 - 사용할 이유가 없습니다.

컴파일러에 RAM 대신 CPU 레지스터를 사용하여 변수를 저장하도록 지시합니다.레지스터는 CPU에 내장되어 있어 RAM보다 액세스 속도가 훨씬 빠릅니다.그러나 이는 컴파일러에 대한 제안일 뿐이며 끝까지 진행되지 않을 수도 있습니다.

이야기 시간!

C는 언어로서 컴퓨터의 추상화이다.컴퓨터의 기능면에서 메모리 조작, 수학, 인쇄 등의 작업을 할 수 있습니다.

하지만 C는 추상화일 뿐이다.그리고 궁극적으로 당신에게서 추출한 것은 어셈블리 언어입니다.어셈블리는 CPU가 읽는 언어이며 이를 사용하면 CPU와 관련된 작업을 수행할 수 있습니다.CPU의 기능기본적으로 메모리에서 읽고, 계산하고, 메모리에 씁니다.CPU는 메모리의 숫자만 계산하는 것이 아닙니다.먼저 레지스터라고 불리는 CPU 내의 메모리 간에 번호를 이동해야 합니다.이 번호에 대해 필요한 작업을 모두 마치면 일반 시스템 메모리로 되돌릴 수 있습니다.시스템 메모리를 사용하는 이유레지스터의 수는 제한되어 있습니다.최신 프로세서에서는 약 100바이트밖에 얻을 수 없습니다.또한 기존의 일반적인 프로세서는 더욱 제한적이었습니다(6502는 3개의 8비트 레지스터를 무료로 사용할 수 있습니다).따라서 평균 산술 연산은 다음과 같습니다.

load first number from memory
load second number from memory
add the two
store answer into memory

그 많은 것들이...수학이 아니다.이러한 로드 및 저장 작업은 처리 시간의 절반까지 소요될 수 있습니다.C는 컴퓨터의 추상화이기 때문에 프로그래머가 레지스터를 사용하고 저글링하는 걱정을 덜어주었고, 컴퓨터마다 수와 종류가 다르기 때문에 C는 레지스터 할당의 책임을 컴파일러에게만 맡겼다.한 가지 예외는 있다.

register컴파일러에게 "Yo, 저는 이 변수를 많이 사용하거나 단명하거나 둘 다 할 것입니다.나라면 장부에 넣어둘 거야.컴파일러가 실제로 아무것도 할 필요가 없다고 하는 것은 C 표준이 컴파일러가 컴파일 하는 컴퓨터를 인식하지 않기 때문입니다.6502년이 경우 3개의 레지스터는 동작에만 필요하고 번호를 유지하기 위한 스페어 레지스터는 없습니다.그러나 주소를 받을 수 없다고 하는 것은 레지스터에 주소가 없기 때문입니다.프로세서의 손입니다.컴파일러는 당신에게 주소를 줄 필요가 없고, 주소를 가질 수도 없기 때문에, 현재 컴파일러에 몇 가지 최적화가 열려 있습니다.예를 들어, 그 번호를 항상 레지스터에 보관할 수 있습니다.컴퓨터 메모리의 어디에 격납되어 있는지에 대해서는 걱정할 필요가 없습니다(다시 회수할 필요가 있는 것 이외).프로세서에 의 작업을 수행할 수 .

tl;dr: 많은 계산을 수행하는 단수명 변수입니다.한꺼번에 너무 많이 신고하지 마세요.

이 질문은 C에 관한 것으로 알고 있습니다만, C++에 대한 질문은 이 질문의 중복과 동일하게 종료되었습니다.따라서 이 답변은 C에는 적용되지 않을 수 있습니다.


C++11 표준의 최신판인 N3485에서는, 7.1.1/3 로 다음과 같이 기술되고 있습니다.

A registerspecifier는 이렇게 선언된 변수가 많이 사용됨을 구현에 대한 힌트입니다.[주의:힌트는 무시할 수 있으며 대부분의 구현에서 변수의 주소가 사용되면 무시됩니다.이 사용은 더 이상 사용되지 않습니다...: end note ]

C++에서는 (C에서는 제외) 표준에는 선언된 변수의 주소를 받을 수 없다고 명시되어 있지 않습니다.register CPU 있는 가 없기 에 해당 무효가 는 CPU를 register키워드를 지정해, 주소를 취득할 수 있습니다.

최적화에 사용되고 있다고 읽었지만, 어느 표준에도 명확하게 정의되어 있지 않습니다.

사실 그것은 C규격에 의해 명확하게 정의되어 있다.N1570 드래프트 섹션 6.7.1 단락 6을 인용합니다(다른 버전에서도 동일한 문구가 사용됨).

스토리지 클래스 지정자가 있는 개체의 식별자를 선언하면 개체에 대한 액세스가 가능한 한 빠를 수 있습니다.그러한 제안이 효과적인 정도는 구현에 정의된다.

★★★&는 operator로 할 수 .register , , , , 입니다.register외부 선언에서는 사용할 수 없습니다.

밖에도 ' 애매한'이 몇 .register- objects: - " 객체":

  • 어레이 오브젝트의 정의 register에 정의되지 않은 동작이 있습니다.
    수정:어레이 오브젝트를 정의하는 것은 합법입니다.register단, 이러한 오브젝트에서는 유용한 조작을 할 수 없습니다(어레이에 들어가려면 초기 요소의 주소를 취득해야 합니다).
  • _Alignas지정자(C11에서 신규)는 이러한 오브젝트에는 적용되지 않을 수 있습니다.
  • 이 「」에 .va_start는 「」입니다.register되어 있지 않습니다.-qualified, qualified, qualified, qualified, quality, quality.

그 밖에도 몇 가지 있습니다.표준 초안을 다운로드하여 관심 있는 경우 "등록"을 검색하십시오.

이름에서 알 수 있듯이 본래의 의미는register오브젝트를 CPU 레지스터에 저장해야 한다는 것이었습니다.그러나 컴파일러의 최적화가 개선됨에 따라 이 기능은 유용하지 않게 되었습니다.최신 버전의 C 규격은 CPU 레지스터를 참조하지 않습니다.이는 더 이상 CPU 레지스터가 존재한다고 가정할 필요가 없기 때문입니다(레지스터를 사용하지 않는 아키텍처가 있습니다).으로는 '적용하다'라는 말이 .register컴파일러 자신의 레지스터 할당을 방해하기 때문에 생성된 코드를 악화시킬 가능성이 높습니다.여전히 유용한 경우가 몇 개 있을 수 있습니다(예를 들어, 변수의 액세스 빈도를 알고 있는 경우, 최신 최적화 컴파일러보다 지식이 더 우수합니다).

주요 가시적 효과register오브젝트의 주소를 수신하는 시도를 막는다는 것입니다.이것은 로컬 변수에만 적용될 수 있고 최적화 컴파일러는 이러한 객체의 주소가 사용되지 않음을 스스로 확인할 수 있기 때문에 최적화 힌트로서 특별히 유용하지는 않습니다.

최적화 플래그를 사용하지 않은 gcc 9.3 asm 출력(이 답변의 모든 내용은 최적화 플래그 없이 표준 컴파일을 참조):

#include <stdio.h>
int main(void) {
  int i = 3;
  i++;
  printf("%d", i);
  return 0;
}
.LC0:
        .string "%d"
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-4], 3
        add     DWORD PTR [rbp-4], 1
        mov     eax, DWORD PTR [rbp-4]
        mov     esi, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        mov     eax, 0
        leave 
        ret
#include <stdio.h>
int main(void) {
  register int i = 3;
  i++;
  printf("%d", i);
  return 0;
}
.LC0:
        .string "%d"
main:
        push    rbp
        mov     rbp, rsp
        push    rbx
        sub     rsp, 8
        mov     ebx, 3
        add     ebx, 1
        mov     esi, ebx
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        add     rsp, 8
        pop     rbx
        pop     rbp
        ret

로 인해 " "가 강제됩니다.ebx계산에 사용됩니다.즉, 콜처가 저장되기 때문에 스택에 푸시하여 함수 끝에 복원해야 합니다. register는 더 및 의 메모리실제로는 이 1에서 0 R될 수 ).esiC++ 를 사용하면, 이것이 실행됩니다.미사용register는 2개의 기입과 1개의 읽기를 일으킵니다(단, 읽었을 때 저장 로드 전송이 발생합니다).이는 올바른 값을 주소(포인터)로 읽을 수 있도록 값이 스택에 직접 존재하고 업데이트되어야 하기 때문입니다. register이 요건이 없기 때문에 지적할 수 없습니다. const ★★★★★★★★★★★★★★★★★」register으로는 volatile and and를 합니다.volatile 및 와 "파일 및 블록 범위"의 "최적화"를 덮어씁니다.register최적화를 실현합니다. const register ★★★★★★★★★★★★★★★★★」register 않기 에 const는 C에 만 동작하기 때문에 동일한 됩니다.register최적화가 적용됩니다.

하면, 쨍그랑 소리가 요.register만, 「」라고 하는 것은,const이치노

실제로 레지스터는 컴파일러에 변수가 프로그램 내의 다른 어떤 것과도 별칭을 짓지 않는다는 것을 알려준다.

이는 다양한 상황에서 최신 컴파일러에 의해 이용될 수 있으며 복잡한 코드로 컴파일러에 큰 도움이 됩니다.간단한 코드로 컴파일러가 스스로 해결할 수 있습니다.

그렇지 않으면 아무런 목적도 없으며 레지스터 할당에도 사용되지 않습니다.컴파일러가 충분히 최신 버전인 한 일반적으로 이를 지정해도 성능 저하가 발생하지 않습니다.

다음 코드를 사용하여 QNX 6.5.0에서 register 키워드를 테스트했습니다.

#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <sys/neutrino.h>
#include <sys/syspage.h>

int main(int argc, char *argv[]) {
    uint64_t cps, cycle1, cycle2, ncycles;
    double sec;
    register int a=0, b = 1, c = 3, i;

    cycle1 = ClockCycles();

    for(i = 0; i < 100000000; i++)
        a = ((a + b + c) * c) / 2;

    cycle2 = ClockCycles();
    ncycles = cycle2 - cycle1;
    printf("%lld cycles elapsed\n", ncycles);

    cps = SYSPAGE_ENTRY(qtime) -> cycles_per_sec;
    printf("This system has %lld cycles per second\n", cps);
    sec = (double)ncycles/cps;
    printf("The cycles in seconds is %f\n", sec);

    return EXIT_SUCCESS;
}

다음과 같은 결과를 얻었습니다.

-> 807679611 사이클 경과

-> 이 시스템의 사이클은 3300830000/초입니다.

-> 사이클(초)은 ~0.244600 입니다.

이제 등록 int를 사용하지 않습니다.

int a=0, b = 1, c = 3, i;

취득:

-> 1421694077 사이클 경과

-> 이 시스템의 사이클은 3300830000/초입니다.

-> 사이클(초)은 ~0.430700 입니다.

비교를를 실시합니다.「 」 「 」 「 」 「 」( 「 」)를 는, 다음과 같습니다.register이 코드 조각은 i7(GCC)에서 3.41초 걸립니다. register0.7로 하다

#include <stdio.h>

int main(int argc, char** argv) {

     register int numIterations = 20000;    

     register int i=0;
     unsigned long val=0;

    for (i; i<numIterations+1; i++)
    {
        register int j=0;
        for (j;j<i;j++) 
        {
            val=j+i;
        }
    }
    printf("%d", val);
    return 0;
}

낙관론자들이 당신보다 더 나은 결정을 내리기 때문에 적어도 15년간은 관련이 없었다.SPARC나 M68000과 같은 레지스터가 많은 CPU 아키텍처에서는 대부분의 레지스터가 컴파일러에 의해 자체 목적을 위해 예약되어 있는 인텔보다 훨씬 더 의미가 있었습니다.

컴파일러의 정교한 그래프 컬러링 알고리즘을 조작하고 있습니다.레지스터 할당에 사용됩니다.뭐, 대부분이요.컴파일러에 대한 힌트로서 기능합니다.맞습니다.그러나 레지스터 변수의 주소를 받을 수 없기 때문에 그 전체가 무시되는 것은 아닙니다(컴파일러는 이제 당신의 자비에 따라 다르게 행동하려고 합니다).어떤 면에서는 사용하지 말라고 하는 거죠

키워드는 아주 오래 전에 사용되었습니다.집게손가락으로 다 셀 수 있는 레지스터가 아주 적었을 때.

하지만 아까도 말씀드렸듯이, 추천을 받지 않는다고 해서 사용할 수 없는 것은 아닙니다.

70년대에 C언어의 첫머리에 register 키워드가 도입되어 프로그래머가 컴파일러에 힌트를 주고 변수가 매우 자주 사용되므로 프로세서의 내부 레지스터 중 하나에 값을 유지하는 것이 현명하다는 것을 알려주고 있습니다.

오늘날 옵티마이저는 레지스터에 저장될 가능성이 높은 변수를 결정하는 데 프로그래머보다 훨씬 효율적이며, 옵티마이저는 프로그래머의 힌트를 항상 고려하는 것은 아니다.

그래서 많은 사람들이 register 키워드를 사용하지 말라고 잘못 권하고 있다.

왜 그런지 보자!

register 키워드에는 관련된 부작용이 있습니다.레지스터 타입 변수를 참조(주소 취득)할 수 없습니다.

다른 사람들에게 레지스터를 사용하지 말라고 조언하는 사람들은 이것을 추가 인수로 잘못 받아들인다.

다만, 레지스터 변수의 주소를 취득할 수 없다는 단순한 사실에 의해서, 컴파일러(및 그 옵티마이저)는, 포인터를 개입시켜 이 변수의 값을 간접적으로 변경할 수 없는 것을 알 수 있습니다.

명령 스트림의 특정 지점에서 레지스터 변수가 프로세서의 레지스터에 할당된 값을 가지며, 그 이후 다른 변수의 값을 얻기 위해 레지스터가 사용되지 않을 때 컴파일러는 해당 레지스터에서 변수 값을 다시 로드할 필요가 없음을 안다.이것에 의해, 고가의 불필요한 메모리 액세스를 회피할 수 있습니다.

독자적인 테스트를 실시하면, 대부분의 내부 루프에서 퍼포먼스가 큰폭으로 향상됩니다.

c_register_side_effect_performance_boost

레지스터는 이 변수가 변수 사용에 사용 가능한 몇 안 되는 레지스터 중 하나에 저장될 만큼 충분히 쓰여지고 읽혀질 것이라고 코더가 컴파일러에 알립니다.일반적으로 레지스터에서 읽기/쓰기가 더 빠르며 더 작은 op-code 세트가 필요할 수 있습니다.

대부분의 컴파일러의 옵티마이저는 해당 변수에 대해 레지스터를 사용해야 하는지, 얼마나 오랫동안 사용해야 하는지를 결정하는 데 있어 사용자보다 더 뛰어나기 때문에 이 기능은 그다지 유용하지 않습니다.

지원되는 C 컴파일러에서는 변수의 값이 실제 프로세서 레지스터에 유지되도록 코드를 최적화하려고 합니다.

C® Visual C++ 를 합니다.register글로벌 레지스터 할당 최적화(/Oe 컴파일러 플래그)가 활성화되어 있는 경우 키워드를 지정합니다.

MSDN 의 register 키워드를 참조해 주세요.

Register 키워드는 컴파일러에게 특정 변수를 CPU 레지스터에 저장하도록 지시합니다.이것에 의해, 액세스 속도가 빨라집니다.프로그래머의 관점에서는 프로그램에서 많이 사용되는 변수에 register 키워드를 사용하여 컴파일러가 코드를 고속화할 수 있도록 한다.단, 변수를 CPU 레지스터 또는 메인 메모리에 유지할지는 컴파일러에 따라 다릅니다.

레지스터는 특정 변수를 레지스터에 저장한 후 메모리에 저장함으로써 이 코드를 최적화하도록 컴파일러에 지시합니다.컴파일러에 대한 요청이며, 컴파일러는 이 요청을 고려할 수도 있고 고려하지 않을 수도 있습니다.일부 변수에 매우 자주 액세스하는 경우 이 기능을 사용할 수 있습니다.예: 루핑.

또한 변수를 레지스터로 선언하면 메모리에 저장되지 않아 주소를 얻을 수 없습니다.CPU 레지스터에 할당됩니다.

register 키워드는 주로 많이 사용되기 때문에 메모리 대신 프로세서의 레지스터에 지정된 변수를 저장하도록 컴파일러에 요청하는 것입니다.컴파일러가 요청을 무시할 수 있습니다.

언급URL : https://stackoverflow.com/questions/578202/register-keyword-in-c

반응형