삽입식 C의volatile에 대한 설명

3394 단어 내장형 C
volatile의 본질:
(1) 컴파일러의 최적화 방지
프로그램이 어떤 함수에서 변수를 읽을 때, 접근 속도를 높이기 위해 컴파일러는 보통 변수를 한 레지스터에 먼저 읽는데, 레지스터 조작이 가장 빠르다.그리고 나중에 이 변수를 다시 사용해야 할 때 레지스터에서 직접 꺼내고 메모리 주소를 통해 메모리에 접근해서 다시 찾지 않아도 된다.이 변수가 이 함수에서 바뀔 때만 레지스터의 저장소가 업데이트되고 이번 메모리의 변화와 일치할 수 있음을 주의하십시오.변수가 다른 곳, 예를 들어 중단, 다른 라인 등에서 바뀔 때 레지스터의 저장소는 업데이트되지 않는다. 이때 레지스터의 값과 실제 값은 일치하지 않는다.그리고volatile 수식은 바로 이런 최적화를 방지하기 위한 것이다.
(2) 메모리 주소에서 직접 액세스
변수가volatile에 수식되었을 때 컴파일러는 변수를 사용할 때 레지스터에서 직접 가져오지 않고 메모리 주소의 값을 직접 가져옵니다. 이런 방법을 통해 얻은 값은 반드시 최신의 실제 값입니다.
volatile는 컴파일러의 컴파일링 결과에 영향을 미친다.volatile 변수는 수시로 변화가 발생할 수 있으며volatile 변수와 관련된 연산은 컴파일 최적화를 하지 마십시오.(VC++는release판 실행 가능한 코드가 발생할 때 컴파일 최적화를 하고volatile 스위치 문자의 변수와 관련된 연산은 컴파일 최적화를 하지 않습니다.)예를 들면 다음과 같습니다.
volatile int i=10; 
int j = i; 
... 
int k = i; 

volatile는 컴파일러 i가 수시로 변할 수 있음을 알려 줍니다. 사용할 때마다 i의 주소에서 읽어야 하기 때문에 컴파일러가 생성한 실행 가능한 코드는 i의 주소에서 데이터를 다시 k에 읽습니다.최적화 방법은 컴파일러가 i에서 데이터를 두 번 읽은 코드 사이의 코드가 i에 대해 조작을 하지 않은 것을 발견하면 지난번에 읽은 데이터를 자동으로 k에 놓는 것이다.다시 i에서 읽는 게 아니라이로써 i가 레지스터 변수이거나 포트 데이터를 표시하면 오류가 발생하기 쉬우므로volatile는 특수 주소에 대한 안정적인 접근을 보장할 수 있고 오류가 발생하지 않는다.
volatile로 정의된 변수는 이 변수가 예상치 못하게 바뀔 수 있다는 것이다. 그러면 컴파일러는 이 변수의 값을 가정하지 않을 것이다.정확히 말하면, 최적화기는 이 변수를 사용할 때, 레지스터에 저장된 백업을 사용하지 않고 매번 조심스럽게 이 변수의 값을 다시 읽어야 한다.다음은volatile 변수의 몇 가지 예이다. 1. 병렬 장치의 하드웨어 레지스터(예를 들어 상태 레지스터) 2, 서비스 중단 서브루틴에서 접근할 수 있는 비자동 변수(Non-automatic variables) 3. 다중 루틴 응용 프로그램에서 몇 개의 임무에 공유된 변수가 이 문제를 대답하지 못하는 사람은 고용되지 않는다.나는 이것이 C 프로그래머와 삽입식 시스템 프로그래머를 구분하는 가장 기본적인 문제라고 생각한다.끼워 넣는 녀석들은 하드웨어, 인터럽트, RTOS 등과 자주 접촉하는데, 이 모든 것들은volatile 변수를 사용해야 한다.volatile의 내용을 모르면 재난을 가져올 수 있다.만약 피면접자가 이것이 문제라고 정확하게 대답했다고 가정한다면 (응, 그럴지 의심된다) 나는 이 녀석이volatile의 완전한 중요성을 직설적으로 알고 있는지 조금 더 깊이 연구해 보겠다.1. 하나의 매개 변수는const일 수도 있고volatile일 수도 있습니까?왜 그런지 설명해.포인터 하나가volatile일 수 있습니까?왜 그런지 설명해.3. 다음 함수에 무슨 오류가 있습니까?
int square(volatile int *ptr) 
{ 
return *ptr * *ptr; 
} 

1. 네.하나의 예는 읽기 전용 상태 레지스터입니다.그것은volatile이다. 왜냐하면 그것은 예상치 못하게 바뀔 수 있기 때문이다.이것은 const입니다. 프로그램이 그것을 수정하려고 시도해서는 안 되기 때문입니다.2. 네.흔하지는 않지만.하나의 예는 버퍼를 가리키는 바늘을 서비스 서브 프로그램이 수정할 때이다.3. 이 코드는 약간 변태적이다.이 코드의 목적은 포인터 ptr가 가리키는 값의 제곱을 되돌리는 데 사용되지만, ptr가volatile형 파라미터를 가리키기 때문에 컴파일러는 다음과 같은 코드를 생성할 것이다.
int square(volatile int *ptr) 
{ 
int a,b; 
a = *ptr; 
b = *ptr; 
return a * b; 
} 

*ptr의 값이 예상치 못하게 변할 수 있기 때문에 a와 b는 다를 수 있습니다.결과적으로, 이 코드는 당신이 원하는 제곱값이 아닐 수도 있습니다.올바른 코드는 다음과 같습니다.
long square(volatile int *ptr) 
{ 
int a; 
a = *ptr; 
return a * a; 
} 

삽입식 프로그래밍에서volatile이라는 키워드를 자주 사용하는데 인터넷에서 그의 사용법을 찾아보면 다음과 같은 두 가지로 요약할 수 있다.
1:compiler에게 최적화할 수 없다고 알려주기
예를 들어 어떤 주소에 두 개의 지령을 보내야 한다.
   int *ip =...; //     
   *ip = 1; //      
   *ip = 2; //      
       compiler       : 
   int *ip = ...; 
   *ip = 2; 

결과적으로 첫 번째 지령이 분실되었다.만약volatile를 사용한다면 compiler는 어떠한 최적화도 허용하지 않고 프로그램의 원래 뜻을 보장합니다.
   volatile int *ip = ...; 
   *ip = 1; 
   *ip = 2; 

설령 당신이compiler를 최적화시키려 한다고 해도, 그것은 두 번의 값 지불 문장을 하나로 간략화하지 않을 것이다.그것은 다른 최적화만 할 수 있다.이것은 device driver 프로그래머에게 매우 유용하다.
2:volatile로 정의된 변수는 프로그램 밖에서 변경되며, 매번 메모리에서 읽어야 하며,cache나 레지스터에 넣고 다시 사용할 수 없습니다.
예컨대
  volatile char a;   
        a=0; 
       while(!a){ 
//do some things;   
       }   
       doother(); 

volatile doother ()가 없으면 실행되지 않습니다.

좋은 웹페이지 즐겨찾기