C에서“등록”키워드?


272

무엇을 않는 registerC 언어에서 할 키워드? 최적화에 사용되었지만 표준에 명확하게 정의되어 있지 않다는 것을 읽었습니다. 여전히 관련이 있습니까? 그렇다면 언제 사용 하시겠습니까?


41
레지스터 키워드는 C에서 무엇을합니까? 무시됩니다 :)
bestsss

18
@bestsss 완전히 무시되지 않았습니다. register변수 의 주소를 얻으십시오 .
qrdl

4
당신이 읽고있는 코드는 오래된 youtube.com/watch?v=ibF36Yyeehw#t=1827
대령 패닉

답변:


340

컴파일러에 변수가 많이 사용되며 가능한 경우 프로세서 레지스터에 보관할 것을 권장합니다.

대부분의 최신 컴파일러는 자동으로 수행하므로 인간보다 컴파일러를 선택하는 것이 좋습니다.


17
글쎄, 나는 ACM 제출을 조정하기 위해 등록을 실험했으며 때로는 실제로 도움이되었습니다. 그러나 선택이 잘못되면 성능이 저하되므로 실제로 조심해야합니다.
ypnos

80
'register'를 사용 하지 않는 좋은 이유 : 'register'로 선언 된 변수의 주소를 사용할 수 없습니다
Adam Rosenfield

22
일부 / 많은 컴파일러는 register 키워드 (완전히 합법적 임)를 완전히 무시합니다.
Euro Micelli

4
ypnos : 실제로 ACM ICPC 문제에 대한 솔루션의 속도는 이러한 미세 최적화보다 알고리즘 선택에 훨씬 더 의존합니다. 5 초의 시간 제한은 일반적으로 올바른 솔루션, 특히 Java 대신 C를 사용할 때 충분합니다.
Joey

65
@Euro : 당신은 아마 이것을 알고 있지만, 명백하게 말하면, register변수 의 주소 가 취해지지 않도록 컴파일러가 필요합니다 . 이것이 키워드 의 유일한 필수 효과입니다 register. 이 기능 내에서만 변수를 수정할 수 있음을 알리는 것이 쉽지 않기 때문에 이것은 최적화를 개선하기에 충분합니다.
Dale Hagglund

69

컴파일러가 레지스터가 아닌 메모리에 변수를 유지하기로 결정하더라도 레지스터 변수의 주소를 사용할 수 없다고 언급 한 사람이 아무도 없습니다.

따라서 register당신을 사용 하면 아무것도 얻지 못하고 (어쨌든 컴파일러는 변수를 넣을 위치를 스스로 결정할 것입니다) &연산자를 잃을 이유가 없습니다.


94
실제로 이유가 있습니다. 변수의 주소를 취할 수 없다는 사실은 컴파일러에게 최적화 기회를 제공합니다. 컴파일러는 변수의 별칭이 지정되지 않음을 증명할 수 있습니다.
Alexandre C.

8
컴파일러는 사소한 경우에 앨리어싱이 발생하지 않는다는 것을 증명하는 데 끔찍한 일이므로 register컴파일러가 레지스터에 넣지 않아도 유용합니다.
Miles Rout

2
@AlexandreC, Miles, 컴파일러는 어디서나 변수를 가져 왔는지 여부를 확인하는 데 완벽합니다. 따라서 앨리어싱 감지에 대한 다른 어려움에 관계없이 휴식을 취하면 아무것도 사지 않습니다. K + R이 처음 C를 만들었을 때 , 컴파일러는 다음 코드를보기 전에 선언을 볼 때 레지스터 할당 결정을 실제로 내렸기 때문에 &가 사용되지 않을 것임을 미리 아는 것이 실제로 유용했습니다 . 이것이 금지가 된 이유입니다. 'register'키워드는 기본적으로 더 이상 사용되지 않습니다.
greggo

25
이 논리 const는 아무것도 얻지 못하기 때문에 쓸모가 없으며 변수를 변경하는 기능 만 잃어 버립니다. register미래에 아무도 생각하지 않고 변수의 주소를 사용하지 않도록하는 데 사용될 수 있습니다. register그래도 사용할 이유가 없었습니다 .
Tor Klingberg

34

컴파일러는 변수를 저장하기 위해 RAM 대신 CPU 레지스터를 사용하도록 컴파일러에 지시합니다. 레지스터는 CPU에 있으며 RAM보다 액세스 속도가 훨씬 빠릅니다. 그러나 이것은 컴파일러에 대한 제안 일뿐이며 따르지 않을 수도 있습니다.


8
C ++를 사용하는 사람들에게 가치가있는 C ++를 사용하면 레지스터 변수의 주소를 사용할 수 있습니다
Will

5
@Will : ...하지만 컴파일러는 결과적으로 키워드를 무시하게됩니다. 내 대답을 참조하십시오.
bwDraco

예, 'register'는 C ++의 위약 인 것 같습니다 .C 코드를 C ++로 컴파일 할 수 있습니다. 그리고 참조 또는 const 참조로 전달하는 동안 & var를 금지하는 것은 의미가 없으며 참조별로 전달하지 않으면 C ++이 심각하게 손상되었습니다.
greggo

22

나는이 질문이 C에 관한 것이라는 것을 알고 있지만 C ++에 대한 동일한 질문 이이 질문의 정확한 복제본으로 닫혔습니다. 따라서이 답변은 C에는 적용되지 않을 수 있습니다.


C ++ 11 표준의 최신 초안 인 N3485 는 이것을 7.1.1 / 3에서 말합니다

register지정 이렇게 선언 된 변수가 많이 사용됩니다한다는 것을 알 수 있습니다. [ note : 힌트는 무시할 수 있으며 대부분의 구현에서 변수의 주소를 가져 오면 무시됩니다. 이 사용은 더 이상 사용되지 않습니다 ... — 끝 참고 ]

C ++에서 (하지만 하지 C에서), 표준하지 않습니다 상태는 변수의 주소를 취할 수 없음을 선언 register; 그러나 수명 동안 CPU 레지스터에 저장된 변수에는 연관된 메모리 위치가 없으므로 해당 주소를 가져 오려고 시도하면 유효하지 않으며 컴파일러는 register키워드를 무시 하여 주소를 가져옵니다.


17

옵티마이 저가 이보다 더 나은 결정을 내릴 때 15 년 이상 관련이 없었습니다. 관련성이 있었더라도 SPARC 또는 M68000과 같은 레지스터가 많은 CPU 아키텍처에서는 레지스터가 부족한 인텔보다 많은 레지스터를 사용했으며, 대부분 자체 컴파일러가 자체 목적으로 예약했습니다.


13

실제로 register는 컴파일러에게 변수가 프로그램의 다른 어떤 것과도 별명을 가지지 않는다는 것을 알려줍니다 (char조차 포함하지 않음).

그것은 다양한 상황에서 현대의 컴파일러에 의해 이용 될 수 있으며 복잡한 코드에서 컴파일러를 상당히 도울 수 있습니다. 간단한 코드에서는 컴파일러가 스스로 알아낼 수 있습니다.

그렇지 않으면 목적이 없으며 레지스터 할당에 사용되지 않습니다. 컴파일러가 최신 버전 인 한 일반적으로 성능을 저하시키지 않습니다.


"컴파일러에게 알려줍니다."아니오, 그렇지 않습니다. 당신의 주소를 가지고하지 않는 한 모든 자동 변수는 해당 속성을 가지고 특정 분석 가능한 용도를 초과하는 방식을 사용합니다. 따라서 컴파일러는 register 키워드 사용 여부에 관계없이 코드에서이를 알고 있습니다. 이 때문에 '등록'키워드가 불법 이러한 구조를 쉽게 작성할 수 있다는 발생하지만,이 키워드를 사용하지 않는 경우 그나마 같은 방법으로 주소를 가지고, 다음 컴파일러는 여전히 안전 알고있다. 이러한 정보는 최적화에 중요합니다.
greggo

1
@greggo : 너무 나쁜 register주소를 사용하는 것을 금지합니다. 그렇지 않으면 컴파일러가 변수의 주소가 외부 함수에 전달 되었지만 컴파일러가 레지스터 최적화를 적용 할 수있는 경우를 알려주는 것이 유용 할 수 있습니다 (변수는 해당 특정 호출에 대해 메모리로 플러시 되지만 함수가 반환되면 컴파일러는이를 주소를 가져 오지 않은 변수로 다시 처리 할 수 ​​있습니다).
supercat

@ supercat 나는 여전히 컴파일러와 가진 매우 까다로운 대화라고 생각합니다. 이것이 컴파일러에게 알리고 싶다면 첫 번째 변수를 '&'가없는 두 번째 변수에 복사 한 다음 첫 번째 변수를 다시 사용하지 마십시오.
greggo

1
@greggo : 경우에 것을 말하는 barA는 register변수, 컴파일러는 자사의 여가 수도 교체 foo(&bar);와 함께 int temp=bar; foo(&temp); bar=temp;,하지만의 주소를 복용 bar지나치게 복잡한 규칙처럼 보이지 않을 것입니다 다른 대부분의 상황에서 금지 될 것입니다. 만약 변수가 레지스터에 유지 될 수 있다면, 대체는 코드를 더 작게 만들 것입니다. 어쨌든 변수를 RAM에 보관 해야하는 경우 대체하면 코드가 더 커집니다. 컴파일러로 대체 할 것인지에 대한 의문을 남기면 두 경우 모두 더 나은 코드로 이어질 것입니다.
supercat

1
@greggo : register컴파일러가 주소를 가져올 수 있는지 여부에 관계없이 전역 변수에 대한 자격을 허용하면 전역 변수를 사용하는 인라인 함수가 루프에서 반복적으로 호출되는 경우 멋진 최적화가 가능합니다. 루프 반복 사이에 레지스터에 변수를 유지하는 다른 방법을 생각할 수 없습니다.
supercat

13

최적화에 사용되었지만 표준에 명확하게 정의되어 있지 않다는 것을 읽었습니다.

사실 그것은 된다 명확하게 C 표준에 의해 정의. N1570 초안 섹션 6.7.1 단락 6 인용 (다른 버전은 동일한 문구가 있음) :

스토리지 클래스 지정자가있는 오브젝트의 식별자 선언은 오브젝트에 register대한 액세스가 가능한 한 빠르다는 것을 나타냅니다. 이러한 제안이 효과적인 범위는 구현에 따라 다릅니다.

단항 &연산자는로 정의 된 객체에 적용되지 않을 수 registerregister외부 선언에서 사용될 수 없다.

register정규화 된 개체에 고유 한 다른 몇 가지 (정확하게 모호한) 규칙이 있습니다.

  • 배열 객체를 정의하면 register동작이 정의되지 않습니다.
    수정 : 으로 배열 객체를 정의하는 것은 합법적 register이지만 그러한 객체로 유용한 것을 수행 할 수는 없습니다 (배열에 색인을 생성하려면 초기 요소의 주소를 사용해야합니다).
  • _Alignas(C11 신규) 지시자는 그러한 객체에 적용 할 수 없다.
  • va_start매크로에 전달 된 매개 변수 이름 이 register-qualified이면 동작이 정의되지 않습니다.

다른 몇 가지가있을 수 있습니다. 표준 초안을 다운로드하고 관심이 있다면 "등록"을 검색하십시오.

이름에서 알 수 있듯이 원래 의미 register는 객체를 CPU 레지스터에 저장해야 한다는 것입니다 . 그러나 컴파일러 최적화가 개선되면서 유용성이 떨어졌습니다. C 표준의 최신 버전은 CPU 레지스터를 더 이상 참조하지 않습니다. 더 이상 필요하지 않다고 가정하기 때문입니다 (레지스터를 사용하지 않는 아키텍처가 있음). 일반적 register으로 객체 선언에 적용 하면 생성 된 코드가 컴파일러의 레지스터 할당을 방해하기 때문에 생성 된 코드 가 더 나빠질 수 있습니다 . 여전히 유용한 몇 가지 경우가있을 수 있습니다 (예 : 변수에 액세스하는 빈도를 실제로 알고 있고 최신 최적화 컴파일러가 알아낼 수있는 것보다 지식이 더 나은 경우).

주요 유형의 효과 register는 객체의 주소를 가져 오려는 시도를 방지한다는 것입니다. 이것은 로컬 변수에만 적용될 수 있고 최적화 컴파일러는 이러한 객체의 주소가 취해지지 않았 음을 스스로 확인할 수 있기 때문에 최적화 힌트로 특히 유용하지 않습니다.


프로그램의 동작은 실제로 C 표준에 따라 정의되어 있지 않습니까? C ++로 잘 정의되어 있습니까? 나는 그것이 C ++에서 잘 정의되어 있다고 생각합니다.
소멸자

@ 소멸자 : 왜 정의되지 않습니까? register당신이 생각하고있는 경우-한정 배열 객체 가 없습니다 .
키이스 톰슨

죄송합니다. main ()에서 배열 선언에 레지스터 키워드를 쓰는 것을 잊었습니다. C ++로 잘 정의되어 있습니까?
소멸자

register배열 객체 를 정의하는 데 잘못되었습니다 . 내 답변에서 업데이트 된 첫 번째 글 머리 기호를 참조하십시오. 그러한 객체를 정의하는 것은 합법적이지만 아무 것도 할 수 없습니다. 예제 에서 register의 정의에 추가 하면 프로그램은 C에서 불법입니다 (제약 위반). C ++은에 동일한 제한을 두지 않으므로 프로그램은 유효한 C ++입니다 (그러나 사용 은 의미가 없습니다). sregisterregister
키이스 톰슨

@KeithThompson : register키워드는 그러한 변수의 주소를 사용하는 것이 합법적이지만 주소를 가져올 때 변수를 임시로 복사하고 임시에서 다시로드하여 의미에 영향을 미치지 않는 경우에만 유용한 목적을 제공 할 수 있습니다 다음 순서 지점에서. 그러면 컴파일러는 변수가 주소가 취해지는 곳에서 플러시되는 경우 모든 포인터 액세스의 레지스터에 변수가 안전하게 유지 될 수 있다고 가정 할 수 있습니다.
supercat

9

이야기 시간!

언어 인 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컴파일러에게 "이 변수를 많이 사용하거나 짧게 사용하려고합니다. 내가 당신이라면 레지스터에 유지하려고 노력할 것입니다." C 표준이 컴파일러가 실제로 아무것도 할 필요가 없다고 말하면 C 표준은 어떤 컴퓨터를 컴파일하는지 알지 못하기 때문에 위의 6502와 같을 수 있습니다. , 전화 번호를 유지하기위한 예비 레지스터가 없습니다. 그러나 주소를 가질 수 없다는 메시지는 레지스터에 주소가 없기 때문입니다. 그들은 프로세서의 손입니다. 컴파일러는 주소를 제공 할 필요가 없으며, 주소를 전혀 가질 수 없기 때문에 이제 컴파일러에 몇 가지 최적화가 열려 있습니다. 즉, 항상 레지스터에 번호를 유지할 수 있습니다. 그렇지 않습니다 컴퓨터 메모리에 저장된 위치에 대해 걱정할 필요가 없습니다 (다시 다시 가져와야 함). 다른 변수에 펑크를 걸거나 다른 프로세서에 변경하거나 위치 변경 등을 할 수도 있습니다.

tl; dr : 많은 수학을 수행하는 수명이 짧은 변수. 한 번에 너무 많이 선언하지 마십시오.


5

컴파일러의 정교한 그래프 채색 알고리즘이 엉망입니다. 이것은 레지스터 할당에 사용됩니다. 글쎄요. 컴파일러에 대한 힌트 역할을합니다. 그러나 레지스터 변수의 주소를 사용할 수 없으므로 완전히 무시하지 마십시오 (이제 컴파일러는 다르게 행동하려고 시도합니다). 어떤 식 으로든 사용하지 말라고 말하고 있습니다.

키워드는 오래 전부터 사용되었습니다. 집게 손가락으로 모두 계산할 수있는 레지스터가 너무 적을 때.

그러나 내가 말했듯이 더 이상 사용되지 않는다고해서 사용할 수 없다는 의미는 아닙니다.


13
구형 하드웨어 중 일부는 최신 인텔 컴퓨터보다 레지스터가 더 많았습니다. 레지스터 수는 연령과 관련이 없으며 CPU 아키텍처와 관련이 있습니다.
저의 올바른 의견

2
@JUSTMYcorrectOPINION 실제로, X86은 기본적으로 6 개를 가지고 있으며 '등록'에 대한 헌신을 위해 최대 1 개 또는 2 개를 남깁니다. 실제로, 너무 많은 코드가 레지스터가 불량한 시스템에 작성되거나 포팅 되었기 때문에, 이것이 '레지스터'키워드가 위약이되는 데 크게 기여한 것으로 생각됩니다. 여기서 우리는 4 년이 넘었고 x86_64는 14 세로 올랐으며 ARM도 큰 문제입니다.
greggo

4

그냥 비교 (모든 실제 목적없이) 약간의 데모는 다음 제거 할 때 register각 변수 전에 키워드를,이 코드 조각은 내 i7의 (GCC)에 3.41 초 정도 걸립니다 으로 register 0.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;
}

2
gcc 4.8.4 및 -O3을 사용하면 아무런 차이가 없습니다. -O3 40000 반복하지 않고, 내가 얻을 어쩌면 50 밀리 적은 1.5 초 총 시간에,하지만 심지어 statistaclly 중요한 있다면 나도 할 충분한 시간을 실행하지 않았다.
zstewart 2012

CLANG 5.0과 차이는 없으며 플랫폼은 AMD64입니다. (ASM 출력을 확인했습니다.)
ern0

4

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

#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입니다.


2

레지스터는 컴파일러에게이 변수가 변수 사용에 사용할 수있는 소수의 레지스터 중 하나에 저장을 정당화 할만큼 충분히 쓰기 / 읽기를했다고 컴파일러에 알립니다. 레지스터에서 읽기 / 쓰기가 일반적으로 빠르며 더 작은 op 코드 세트가 필요할 수 있습니다.

요즘에는 대부분의 컴파일러 최적화 프로그램이 해당 변수에 레지스터를 사용해야하는지 여부와 시간을 결정하는 것보다 낫기 때문에 유용하지 않습니다.


2

70 년대에 C 언어가 시작될 때 프로그래머가 컴파일러에 힌트를 제공하여 변수가 매우 자주 사용될 것임을 알리고 레지스터를 현명하게 사용해야한다는 것을 알려주기 위해 register 키워드가 도입되었습니다. 프로세서의 내부 레지스터 중 하나에 값을 유지하십시오.

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

많은 사람들이 register 키워드를 사용하지 말 것을 잘못 권장합니다.

이유를 보자!

register 키워드는 관련 부작용이 있습니다. 레지스터 유형 변수를 참조 할 수 없습니다.

다른 사람들에게 레지스터를 사용하지 말라고 조언하는 사람들은 이것을 추가적인 주장으로 잘못 생각합니다.

그러나 레지스터 변수의 주소를 사용할 수 없다는 사실을 알면 컴파일러 (및 최적화 프로그램)가이 변수의 값을 포인터를 통해 간접적으로 수정할 수 없음을 알 수 있습니다.

명령어 스트림의 특정 지점에서 레지스터 변수에 프로세서 레지스터에 값이 할당되어 있고 다른 변수의 값을 얻기 위해 레지스터를 사용하지 않은 경우 컴파일러는 다시로드 할 필요가 없다는 것을 알고 있습니다. 해당 레지스터의 변수 값 이를 통해 값 비싼 쓸모없는 메모리 액세스를 피할 수 있습니다.

자체 테스트를 수행하면 가장 내부 루프에서 성능이 크게 향상됩니다.

c_register_side_effect_performance_boost


1

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


1

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

MSDN에서 키워드 등록을 참조하십시오 .


1

Register 키워드는 컴파일러가 특정 변수를 CPU 레지스터에 저장하여 빠르게 액세스 할 수 있도록합니다. 프로그래머의 관점에서 레지스터 키워드는 프로그램에서 많이 사용되는 변수에 사용되므로 컴파일러가 코드 속도를 높일 수 있습니다. 변수를 CPU 레지스터 또는 메인 메모리에 유지할지 여부는 컴파일러에 따라 다릅니다.


0

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

한 가지 더 중요한 것은 변수를 레지스터로 선언하면 메모리에 저장되지 않으므로 주소를 얻을 수 없다는 것입니다. CPU 레지스터에서 할당을 얻습니다.


0

최적화 플래그를 사용하지 않고 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 개 메모리 쓰기 1 개 메모리 읽기 더 라인을 생산 (현실적으로이 0 R에 최적화 된 수 있지만 / 계산이에서 수행 된 경우 WS esi의 C ++를 사용하여 발생하는 것입니다, const register). 사용하지 않으면 register쓰기 2 회와 읽기 1 회가 발생합니다 (읽기시 저장소로드로드가 발생하더라도). 이는 주소 (포인터)가 올바른 값을 읽을 수 있도록 스택에 직접 값이 존재하고 업데이트되어야하기 때문입니다. register이 요구 사항이 없으며 지적 할 수 없습니다. const그리고 register기본적으로의 반대 volatile및 사용volatile파일 및 블록 범위의 const 최적화와 registerblock-scope 의 최적화를 무시합니다 . const registerregisterCONST 블록 범위 내에서 C에 아무런 역할을하지 않기 때문에, 동일한 출력을 생성 할 정도로 만 register최적화가 적용된다.

clang에서는 register무시되지만 const최적화는 여전히 발생합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.