register 키워드는 실제로 C에서 언제 유용합니까?

C에서 register 키워드를 사용하는 것에 대해 혼란 스럽습니다. 일반적으로 사용하지 않는다고합니다. ” t는 stackoverflow에 대한이 질문 에서처럼 필요했습니다.

이 키워드는 최신 컴파일러로 인해 C에서 완전히 중복됩니까? 그래도 유용 할 수 있습니까? 그렇다면 register 키워드를 사용하는 것이 실제로 도움이되는 상황은 무엇입니까?

댓글

  • 링크 된 질문과 답변이 여기에서 예상 할 수있는 것과 동일하다고 생각합니다. 따라서 여기에서 얻을 수있는 새로운 정보는 없을 것입니다.
  • @UwePlonus const 키워드에 대해서는 동일하지만 이 질문 은 제가 틀렸다는 것을 증명했습니다. 그래서 저는 ‘ 기다리면 내가 무엇을 얻을 수 있는지 볼 수 있습니다.
  • const 키워드가 레지스터와 다른 것 같습니다.
  • 그것 ‘ 실수로 시간을 거슬러 올라가 초기 C 컴파일러 중 하나를 사용해야하는 경우 유용합니다. 그 외에는 ‘ 전혀 유용하지 않지만 ‘는 수년간 완전히 사용되지 않았습니다.
  • @ UwePlonus 키워드가 유용 할 수있는 나에게 알려지지 않은 시나리오가있을 수 있음을 의미했습니다.

답변

언어 측면에서 중복되지 않습니다. 단지 그것을 사용함으로써 컴파일러에게 “변수를 레지스터에 저장하는 것을 선호”할 것이라고 말하는 것입니다. 그러나 이것이 실제로

댓글

  • 그 이상으로 ‘ 거의 항상 컴파일러가 가장 잘 알고 있으며 ‘ 숨을 낭비하고 있습니다
  • @jozefg : 더 나쁩니다. 컴파일러가 요청 / 힌트를 존중하고 과적으로 코드가 더 나빠집니다.

답변

이미 언급했듯이 컴파일러 최적화 프로그램은 기본적으로 르네 register 키워드는 앨리어싱 방지 이외의 목적으로 사용되지 않습니다. 그러나 최적화를 끈 상태에서 컴파일되는 전체 코드베이스가 있습니다 ( gcc-speak -O0). 이러한 코드의 경우 register 키워드가 큰 효과를 낼 수 있습니다. 특히, 그렇지 않으면 스택에서 슬롯을 얻을 수있는 변수 (즉, 모든 함수 매개 변수 및 자동 변수)는 register div로 선언 된 경우 레지스터에 직접 배치 될 수 있습니다 . > 키워드.

실제 예 : 일부 데이터베이스 검색이 발생하고 검색 코드가 검색된 튜플을 C 구조체에 채웠다 고 가정합니다. 또한이 C 구조체의 일부 하위 집합을 가정합니다. 다른 구조체로 복사해야합니다.이 두 번째 구조체는 메모리 제약으로 인해 데이터베이스에 저장된 각 메타 데이터 레코드의 하위 집합 만 캐시하는 데이터베이스에 저장된 메타 데이터를 나타내는 캐시 레코드 일 수 있습니다.

각 구조체 유형에 대한 포인터를 사용하고 초기 구조체에서 두 번째 구조체로 일부 멤버를 복사하는 것이 유일한 작업 인 함수가 제공됩니다. 구조체 포인터 변수는 스택에 있습니다. 할당은 하나의 구조체 멤버에서 발생합니다. 다른 사람에게 구조체의 주소는 각 할당에 대해 복사중인 구조체 멤버의 액세스를 수행하기 위해 레지스터에로드됩니다. 구조체 포인터가 register 키워드로 선언 된 경우 구조체의 주소는 레지스터에 남아있어 각 할당에 대한로드 주소-등록 명령을 효과적으로 제거합니다.

다시 한 번 위의 설명은 최적화되지 않은 코드에 적용됩니다.

Answer

기본적으로 컴파일러에게 변수의 주소를 사용하지 않을 것이라고 말하면 컴파일러가 표면적으로 추가 최적화. 내가 아는 한, 현대 컴파일러는 변수가 레지스터에 보관 될 수 있는지 여부를 결정할 수 있습니다.

예 :

int main(){ int* ptr; int a; register int b; ptr = &a; ptr = &b; //this won"t compile return 0; } 

댓글

  • 해독 또는 주소 사용
  • @detly : 물론 맞습니다.

답변

16 비트 컴퓨터 시대에는 32 비트 곱셈과 나눗셈을 실행하기 위해 종종 여러 레지스터가 필요했습니다. 부동 소수점 단위가 칩에 통합 된 다음 64 비트 아키텍처가 “점령”되어 레지스터의 너비와 개수가 모두 확장되었습니다. 결국 CPU를 완전히 재구성하게됩니다. 파일 등록 은 Wikipedia에 있습니다.

요컨대, figu를 작성하는 데 약간의 시간이 걸립니다. 64 비트 X86 또는 ARM 칩을 사용하는 경우 실제로 무슨 일이 일어나고 있는지 확인하십시오.16 비트 임베디드 CPU를 사용하는 경우 실제로 뭔가를 얻을 수 있습니다. 그러나 대부분의 소형 임베디드 칩은 시간이 중요하지 않습니다. 전자 레인지가 1 초에 10,000 번 터치 패드를 샘플링 할 수 있습니다. 4Mhz CPU.

설명

  • 4 MIPS / 10,000 polls / sec = 400 개의 명령 / 폴. 이 정도는 ‘ 당신이 원하는만큼의 마진이 아닙니다. ‘ 또한 상당수의 4MHz 프로세서가 내부적으로 마이크로 코딩되었으므로 1MIP / MHz 근처에 있지 않다는 것을 의미합니다.
  • @ JohnR.Strohm-얼마나 많은 명령어를 정확히 파악하는 것을 정당화 할 수있는 상황이있을 수 있습니다. ‘를 순환하지만 현재 더 저렴한 방법은 더 빠른 칩을 가져와 제품을 꺼내는 것입니다. 물론 주어진 예에서 ‘ 명령이있는 경우 10,000에서 계속 샘플링 할 필요가 없습니다. 1/4 초 동안 아무런 해없이 샘플링을 재개하지 않을 수도 있습니다. 끝난. 프로그래머 지시 최적화가 어디에서 중요한지 파악하는 것이 점점 더 어려워지고 있습니다.
  • ” 더 빠른 칩을 얻고 제품 출시 “. 실시간 이미지 처리를 고려하십시오. 640×480 픽셀 / 프레임 x 60 프레임 / 초 x 픽셀 당 N 개의 명령이 빠르게 추가됩니다. (실시간 이미지 처리의 교훈은 픽셀 커널을 통해 피를 흘리며 나머지 모든 것을 무시한다는 것입니다. 왜냐하면 라인 당 한 번 또는 패치 당 한 번 또는 프레임 당 한 번 실행되기 때문입니다. 패치 또는 프레임 당 수만 또는 수십만 번.)
  • @ JohnR.Strohm-실시간 이미지 처리 예를 들어 보면 최소 환경이 32 비트라고 가정합니다. 팔다리로 나가는 것 (이 작업이 얼마나 실용적인지 ‘ 알지 못하기 때문에) 칩에 내장 된 많은 그래픽 가속기도 이미지 인식에 사용할 수 있으므로 ARM 칩 (예 : ) 통합 렌더링 엔진이있는 경우 인식에 사용할 수있는 추가 ALU가있을 수 있습니다. 그때까지는 최적화를 위해 ‘ register ‘ 키워드를 사용하는 것이 문제의 작은 부분입니다.

답변

register 키워드에 의미가 있는지 확인하기 위해 작은 예제 코드는 수행하지 않습니다. 다음은 c-code입니다. 제가보기에 register 키워드는 여전히 의미가 있지만 Linux의 GCC와는 다를 수 있습니다. int k & l 레지스터가 CPU 레지스터에 저장됩니까? Linux 사용자 (특히)는 GCC 및 최적화로 컴파일해야합니다. Borland bcc32를 사용하면 &-연산자가 레지스터 선언 정수에 대한 오류 코드를 제공하므로 register 키워드가 작동하는 것처럼 보입니다 (이 예에서). 노트! 이것은 Windows에서 Borland를 사용한 작은 예제의 경우가 아닙니다! 컴파일러가 무엇을 최적화하는지 실제로 확인하려면 작은 예제 이상이어야합니다. 빈 루프는 작동하지 않습니다! 그럼에도 불구하고-&-연산자로 주소를 읽을 수 있다면 변수는 CPU 레지스터에 저장되지 않습니다. 하지만 레지스터 선언 변수를 읽을 수 없다면 (컴파일시 오류 코드가 발생 함)-register 키워드가 실제로 변수를 CPU 레지스터에 넣는 것으로 가정해야합니다. 다양한 플랫폼에서 다를 수 있습니다. . (작동하는 경우 레지스터 선언으로 “틱”수가 훨씬 적습니다.

/* reg_or_not.c */ #include <stdio.h> #include <time.h> #include <stdlib> //not requiered for Linux #define LAPSb 50 #define LAPS 50000 #define MAXb 50 #define MAX 50000 int main (void) { /* 20 ints and 2 register ints */ register int k,l; int a,aa,b,bb,c,cc,d,dd,e,ee,f,ff,g,gg,h,hh,i,ii,j,jj; /* measure some ticks also */ clock_t start_1,start_2; clock_t finish_1,finish_2; long tmp; //just for the workload /* pointer declarations of all ints */ int *ap, *aap, *bp, *bbp, *cp, *ccp, *dp, *ddp, *ep, *eep; int *fp, *ffp, *gp, *ggp, *hp, *hhp, *ip, *iip, *jp, *jjp; int *kp,*lp; /* end of declarations */ /* read memory addresses, if possible - which can"t be done in a CPU-register */ ap=&a; aap=&aa; bp=&b; bbp=&bb; cp=&c; ccp=&cc; dp=&d; ddp=&dd; ep=&e; eep=&ee; fp=&f; ffp=&ff; gp=&g; ggp=&gg; hp=&h; hhp=&hh; ip=&i; iip=&ii; jp=&j; jjp=&jj; //kp=&k; //won"t compile if k is stored in a CPU register //lp=&l; //same - but try both ways ! /* what address , isn"t the issue in this case - but if stored in memory some "crazy" number will be shown, whilst CPU-registers can"t be read */ printf("Address a aa: %u %u\n",a,aa); printf("Address b bb: %u %u\n",b,bb); printf("Address c cc: %u %u\n",c,cc); printf("Address d dd: %u %u\n",d,dd); printf("Address e ee: %u %u\n",e,ee); printf("Address f ff: %u %u\n",f,ff); printf("Address g gg: %u %u\n",g,gg); printf("Address h hh: %u %u\n",h,hh); printf("Address i ii: %u %u\n",i,ii); printf("Address j jj: %u %u\n\n",j,jj); //printf("Address k: %u \n",k); //no reason to try "k" actually is in a CPU-register //printf("Address l: %u \n",l); start_2=clock(); //just for fun /* to ensure workload */ for (a=1;a<LAPSb;a++) {for (aa=0;aa<MAXb;aa++);{tmp+=aa/a;}} for (b=1;b<LAPSb;b++) {for (bb=0;bb<MAXb;bb++);{tmp+=aa/a;}} for (a=1;c<LAPSb;c++) {for (cc=0;cc<MAXb;cc++);{tmp+=bb/b;}} for (d=1;d<LAPSb;d++) {for (dd=0;dd<MAXb;dd++);{tmp+=cc/c;}} for (e=1;e<LAPSb;e++) {for (ee=0;ee<MAXb;ee++);{tmp+=dd/d;}} for (f=1;f<LAPSb;f++) {for (ff=0;ff<MAXb;ff++);{tmp+=ee/e;}} for (g=1;g<LAPSb;g++) {for (gg=0;gg<MAXb;gg++);{tmp+=ff/f;}} for (h=1;h<LAPSb;h++) {for (hh=0;hh<MAXb;hh++);{tmp+=hh/h;}} for (jj=1;jj<LAPSb;jj++) {for (ii=0;ii<MAXb;ii++);{tmp+=ii/jj;}} start_1=clock(); //see following printf for (i=0;i<LAPS;i++) {for (j=0;j<MAX;j++);{tmp+=j/i;}} /* same double loop - in supposed memory */ finish_1=clock(); //see following printf printf ("Memory: %ld ticks\n\n", finish_1 - start_1); //ticks for memory start_1=clock(); //see following printf for (k=0;k<LAPS;k++) {for (l=0;l<MAX;l++);{tmp+=l/k;}} /* same double loop - in supposed register*/ finish_1=clock(); //see following printf printf ("Register: %ld ticks\n\n", finish_1 - start_1); //ticks for CPU register (?) any difference ? finish_2=clock(); printf ("Total: %ld ticks\n\n", finish_2 - start_2); //really for fun only system("PAUSE"); //only requiered for Windows, so the CMD-window doesn"t vanish return 0; } 

댓글

  • 위에 0이있는 구분이있을 것입니다. {tmp + = ii / jj;}를 {tmp + = jj / ii;}로 변경하십시오-정말 죄송합니다
  • 또한 k와 i 0이 아닌 1로 시작합니다. 매우 죄송합니다.
  • 댓글에 수정 사항을 작성하는 대신 답변을 수정할 수 있습니다.

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다