C 언어에서 키워드volatile의 의미를 탐구하다

5533 단어
volatile의 뜻은'잃기 쉽고 바꾸기 쉽다'는 것이다.이 한정어의 의미는 컴파일러에게 변수의 내용이 다른 프로그램의 수정으로 인해 바뀔 수 있음을 가리키는 것이다.보통 프로그램에서 변수를 설명할 때, 컴파일러는 ebx와 같은 일반적인 레지스터에 최대한 저장합니다.CPU가 ebx에 값을 넣으면 메모리에 대응하는 값에 더 이상 관심이 없습니다.만약 이 때 다른 프로그램 (예를 들어 내장 프로그램이나 인터럽트) 이 메모리의 값을 수정한다면, ebx의 값은 업데이트되지 않을 것입니다.이러한 상황을 해결하기 위해volatile 한정어를 만들었습니다. 코드가 이 변수를 인용할 때 반드시 지정한 위치에서 그 값을 얻어야 합니다.
키워드volatile는 어떤 의미가 있습니까?그리고 세 가지 다른 예를 제시한다.volatile로 정의된 변수는 이 변수가 예상치 못하게 바뀔 수 있다는 것이다. 그러면 컴파일러는 이 변수의 값을 가정하지 않을 것이다.정확히 말하면, 최적화기는 이 변수를 사용할 때, 레지스터에 저장된 백업을 사용하지 않고 매번 조심스럽게 이 변수의 값을 다시 읽어야 한다.다음은volatile 변수의 몇 가지 예입니다.
1). 병렬 장치의 하드웨어 레지스터 (예: 상태 레지스터) 2.인터럽트 서비스 서브루틴에서 접근할 수 있는 비자동 변수 (Non-automatic variables) 3.다중 스레드 응용 프로그램에서 몇 개의 임무가 공유하는 변수에 의해 이 문제를 대답하지 못하는 사람은 고용되지 않는다.나는 이것이 C 프로그래머와 삽입식 시스템 프로그래머를 구분하는 가장 기본적인 문제라고 생각한다.삽입식 시스템 프로그래머는 하드웨어, 중단, RTOS 등과 자주 접촉하는데 이런 것들은volatile 변수를 요구한다.volatile 내용을 모르면 재난을 가져올 수 있다.
만약 피면접자가 이것이 문제라고 정확하게 대답했다고 가정한다면 (응, 이것이 그럴지 의심스럽다) 나는 이 녀석이volatile의 완전한 중요성을 직설적으로 알고 있는지 조금 더 깊이 연구해 보겠다.
1). 하나의 매개 변수는 const일 수도 있고volatile일 수도 있습니까?왜 그런지 설명해.2). 바늘 하나가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의 본뜻은'변하기 쉽다'는 것이다
액세스 레지스터의 속도가 RAM보다 빠르기 때문에 컴파일러는 일반적으로 외부 RAM에 대한 접근을 줄이는 최적화를 한다.예를 들면 다음과 같습니다.
 
  
static   int   i=0;
int   main(void)
{
        ...
        while   (1)
        {
                if   (i)   dosomething();
        }
}
/*   Interrupt   service   routine.   */
void   ISR_2(void)
{
          i=1;
}

프로그램의 본뜻은 ISR2 인터럽트 발생 시,main에서dosomething 함수를 호출하지만, 컴파일러는main 함수에서 i를 수정한 적이 없다고 판단하기 때문에
i에서 어떤 레지스터에 대한 읽기 동작을 한 번만 수행할 수 있으며, 매번if판단이 이 레지스터 안의 'i 던전' 만 사용해서dosomething이 영원히 호출되지 않을 수도 있습니다.변수에volatile 수식을 더하면 컴파일러는 이 변수의 읽기와 쓰기 작업이 최적화되지 않을 것을 보장합니다. (틀림없이 실행될 것입니다.)이 예에서 i도 반드시 이렇게 설명해야 한다.
일반적으로volatile은 다음과 같은 몇 가지 곳에 사용된다.
1. 서비스 프로그램에서 수정된 다른 프로그램이 감지할 수 있는 변수는volatile를 추가해야 한다.2. 다중 임무 환경에서 각 임무 간에 공유하는 표지는volatile을 넣어야 한다.3. 메모리에 비치는 하드웨어 레지스터도volatile 설명을 넣어야 한다. 왜냐하면 매번 그것에 대한 읽기와 쓰기는 서로 다른 의미가 있을 수 있기 때문이다.또한 상기 몇 가지 상황은 데이터의 완전성을 동시에 고려해야 한다.
현재 2에서는 임무 스케줄링을 금지할 수 있고, 3에서는 하드웨어의 양호한 설계에 의존할 수밖에 없다.
//=============
바늘 유형도 변수이기 때문에volatile로 수식할 수 있습니다.
volatile 키워드는 형식 수식자입니다. 형식 변수는 일부 컴파일러가 알 수 없는 요소에 의해 변경될 수 있음을 나타냅니다. 예를 들어
운영체제, 하드웨어 또는 기타 라인 등.이 키워드가 설명하는 변수를 만나면 컴파일러가 이 변수에 접근하는 코드를 더 이상 진행하지 않습니다
최적화되어 특수 주소에 대한 안정적인 접근을 제공할 수 있다.
이 키워드를 사용하는 예는 다음과 같습니다.
int   volatile   nVint; volatile에서 설명한 변수의 값을 사용하도록 요구할 때, 시스템은 항상 자신이 있는 메모리에서 데이터를 다시 읽습니다.
방금 이 곳에서 데이터를 읽었습니다.그리고 읽은 데이터는 즉시 저장됩니다.
예: volatile int i=10;
int   a   =   i;
...//기타 코드는 컴파일러에게 명확하게 알리지 않고 i에 대해 조작했다
int   b   =   i;
volatile는 i는 수시로 변할 수 있으며, 사용할 때마다 i의 주소에서 읽어야 하기 때문에 컴파일러가 생성한 것이다
어셈블리 코드는 i의 주소에서 데이터를 다시 b에 저장합니다.최적화 방법은 컴파일러가 i에서 데이터를 두 번 읽는 코드 사이를 발견했기 때문이다
의 코드는 i를 조작한 적이 없습니다. 이것은 지난번에 읽은 데이터를 자동으로 b에 저장합니다.다시 i에서 읽는 게 아니라하면, 만약, 만약...
i는 레지스터 변수이거나 포트 데이터가 잘못되기 쉬우므로volatile는 특수 주소에 대한 안정적인 접근을 보장할 수 있습니다.
주의,vc6에서 일반 디버깅 모드는 코드 최적화를 하지 않았기 때문에 이 키워드의 역할을 알 수 없습니다.다음은 어셈블리 삽입을 통해
코드, volatile 키워드가 프로그램 최종 코드에 미치는 영향을 테스트합니다.
우선classwizard로 win32 console 프로젝트를 만들고voltest를 삽입합니다.cpp 파일, 다음 코드를 입력합니다.
 
  
#include  
void   main()
{
  int   i=10;
  int   a   =   i;
  printf( "i=   %d
",a);
                // i ,
  __asm   {
    mov                   dword   ptr   [ebp-4],   20h
  }
  int   b   =   i;
  printf( "i=   %d
",b);
}

그런 다음 디버그 버전 모드에서 프로그램을 실행하면 다음과 같은 결과가 출력됩니다.
 
  
i   =   10
i   =   32

그런 다음 release 버전 모드에서 프로그램을 실행하면 다음과 같은 결과가 출력됩니다.
 
  
i   =   10
i   =   10

출력 결과에 따르면release 모드에서 컴파일러가 코드를 최적화했고 두 번째로 정확한 i값을 출력하지 못했다.
다음은 i의 성명에volatile 키워드를 더해서 어떤 변화가 있는지 봅시다.
 
  
#include  
void   main()
{
  volatile   int   i=10;
  int   a   =   i;
  printf( "i=   %d
",a);
  __asm   {
    mov                   dword   ptr   [ebp-4],   20h
  }
  int   b   =   i;
  printf( "i=   %d
",b);
}

디버그 버전과 release 버전에서 각각 프로그램을 실행합니다. 출력은 다음과 같습니다.
 
  
i   =   10
i   =   32
이것은 이 키워드가 그 역할을 발휘했다는 것을 설명한다!

좋은 웹페이지 즐겨찾기