보통의 지역 변수, auto를 사용하여 선언된 지역 변수, register를 사용하여 선언된 지역변수
같은 점 | 자동 기억 존속 시간, 지역 사용 범위를 가짐. 다른 번역 단위들에 이름을 공유할 수 없다 |
다른 점 | register 제한자를 사용하면 변수가 메모리 스택이 아닌 CPU 레지스터 등에 저장된다 |
문제점: 아래와 같은 내용을 발견할 수 있었다
== register 변수
변수는 보통 컴퓨터의 메모리에 저장된다. 그러나 운이 좋으면 레지스터 변수는 CPU 레지스터 또는 더 일반적으로 가장 빠른 메모리에 저장되는데, 보통 변수보다 더 빠르게 접근하고 계산될 수 있다. 이외의 부분들은 자동변수와 똑같다. 이때 운이 좋으면 이라고 표현한 것은 레지스터 변수의 수가 제한되기 때문이다. 컴파일러는 레지스터 수와 선언된 변수의 수를 가중치에 따라 조정하기 때문에 레지스터 변수로 선언했지만 자동 변수로 되는 경우도 있을 수 있다. 그리고 레지스터 변수로 선언될 수 있는 형도 제한이 있다. 또한 & 연산자도 레지스터 변수에는 적용할 수 없다.
즉, 실제 레지스터 변수로 선언을 해도 레지스터 변수로 사용될지 안될지는 알 수 없다.
위의 코드를 실행했을 때 레지스터의 변화는 아래와 같았다.
어셈블리 코드만으로 비교를 해보면 레지스터 변수와 일반 변수의 차이를 알 수 없었다. 해당 내용을 알 기 위해선 레지스터 값을 비교해 보았다
자동변수를 선언했을 때는 아래와 같이 값이 메모리에 저장되는걸 볼 수 있었다
그러나 레지스터 변수를 선언한 경우는 EAX에 값이 저장되는 걸로 파악되었다.
레지스터 변수에 대한 추가적인 내용은 아래와 같았다(출처: http://blog.daum.net/zzigee/5116707)
프로그램을 코딩하는 중에 자주 쓰는 변수들을 register 변수로 선언하여 사용한다. 하지만 똑똑한 Compiler는 직접 선언해 주지 않아도 register 변수로 잡기도 한다(Compiler에 의한 최적화 수행). Memory Mapped I/O(메모리의 특정 영역을 특정 장치와 연결해서 사용)의 경우에는 문제가 발생한다. 왜냐하면, 어떤 장치의 한 영역을 나타내는 변수가 있고 이 변수를 통하여 그 장치의 상황을 받아들여 특정한 일을 처리하는 경우 당연히 이 변수는 자주 쓰이는 변수가 되므로 Compiler에 의해서 Register 변수로 처리가 될 수 있는데 이를 미연에 방지하고자 volatile이라는 Keyword를 주게 되면 Compiler는 이 변수에 대한 최적화를 수행하지 않게 된다. 따라서, 원하는 결과를 얻을수 있게 된다.
메모리 변수(volatile variable)는 지역 변수를 선언할 때 레지스터가 아닌 반드시 메모리에 변수를 만들어 처리하도록 한다. 그러면 "할 수 있다면 빠른 레지스터 변수를 사용하는 것이 더 낫지 않느냐?" 라는 반론이 제기될 수 있는데 일반적으로 메모리 변수는 인터럽트 루틴 등의 변수에 사용된다. 레지스터 변수인 경우 인터럽트 루틴에서 그 변수의 내용을 바꾸면 레지스터에 있는 값이 바뀌므로 언제 그 레지스터의 값이 없어질지 알 수 없다. 이런 경우 메모리 변수로 선언하기 위해 volatile을 사용한다.
volatile은 컴파일러 키워드이다. 특별히 따로 최적화를 하지 않고 쓴대로 수행시키라는 의미이다. 함수에 이것이 있으면 함수 내부를 컴파일할때 최적화 옵션이 있어도 최적화를 수행 하지 않는다. 변수에 이것이 붙으면 속도를 위해서 변수를 레지스터에 올려놓고 쓰는일 같은 것을 안하게 된다. 보통 IO Port를 특별한 변수 이름으로 지정해놓고 사용하고자 할때 volatile키워드를 붙여서 쓴다.
일반적으로 컴파일러는 최적화를 하는 동안 불필요 하다고 생각되는 코드를 생략을 하게된다. 그러나 volatile을 사용하는 경우 이 변수와 관련된 내용은 생략하지 않는다. 키워드 volatile이 정의되어 있지 않으면 컴파일러는 마지막 명령만 남기고 이전 명령들을 생략할 수 있다.
예)char * Addr;
Addr = (char *)0x10000;
*Addr = 0x55; /*생략한다..*/
*Addr = 0xAA; /* 이것만 인식한다*/위의 경우 단지 0x10000에 0xAA만 쓴 것으로 컴파일러는 생각하게 된다. 일반적으로 같은 곳에 값을 써주거나 값을 읽을 일이 많은 메모리나 레지스터인 경우에는 volatile를 써주는 것이 좋다. 만약 컴파일러가 최적화 옵션을 사용하지 않는다면 써줄 필요는 없다.
volatile 선언은 디버그 모드에서는 작동하지 않고 보통 릴리즈 모드에서 최적화시에 발생한다. 쉬운 예를 들자면 for (;;) { int a = 1; .. .. } 이렇게 되어 있을때. 이 루프가 한 100만번 돈다고 하면. int a = 1;은 루프 밖으로 빼는게 실행 속도가 빨라진다. 컴파일러는 자기가 알아서 이런 것을 루프 밖으로 빼버린다. 그런데 이 문장을 빼는 것이 큰 문제가 되는 경우도 있다. 이럴때 volatile int a = 1 해주면 최적화 대상에서 제외 된다.
댓글 없음:
댓글 쓰기