const와 const volatile의 차이점


89

volatile새로운 값이 업데이트 될 때마다 변수를
선언하면 변수를 const다음과 같이 선언하면 해당 변수의 값은 변경되지 않습니다.

그러면 위와 같이 const volatile int temp;
변수 temp를 선언하는 용도는 무엇입니까 ?
다음과 같이 선언하면 어떻게됩니까 const int temp?


당신은 const volatile int temp;블록 범위에서 사용하지 않을 것입니다 (즉, 내부 { }), 거기에서 사용하지 않습니다.
MM

답변:


145

로 표시된 객체 const volatile는 코드에 의해 변경이 허용되지 않습니다 ( const한정자 로 인해 오류가 발생 함 )-적어도 해당 이름 / 포인터를 통해.

volatile한정자 의 일부는 컴파일러가 개체에 대한 액세스를 최적화하거나 재정렬 할 수 없음을 의미합니다.

임베디드 시스템에서 이는 일반적으로 하드웨어에서 읽고 업데이트 할 수있는 하드웨어 레지스터에 액세스하는 데 사용되지만 쓰기에는 의미가 없습니다 (또는 쓰기 오류 일 수 있음).

직렬 포트의 상태 레지스터를 예로들 수 있습니다. 문자가 읽기를 기다리고 있는지 또는 전송 레지스터가 새 문자를받을 준비가되었는지 (즉, 비어 있음) 다양한 비트가 표시됩니다. 이 상태 레지스터를 읽을 때마다 직렬 포트 하드웨어에서 발생한 다른 작업에 따라 다른 값이 나올 수 있습니다.

(특정 하드웨어 사양에 따라) 상태 레지스터에 쓰는 것은 의미가 없지만 레지스터를 읽을 때마다 하드웨어의 실제 읽기가 발생하는지 확인해야합니다. 이전 읽기에서 캐시 된 값을 사용하면 t 하드웨어 상태의 변화에 ​​대해 알려줍니다.

간단한 예 :

unsigned int const volatile *status_reg; // assume these are assigned to point to the 
unsigned char const volatile *recv_reg;  //   correct hardware addresses


#define UART_CHAR_READY 0x00000001

int get_next_char()
{
    while ((*status_reg & UART_CHAR_READY) == 0) {
        // do nothing but spin
    }

    return *recv_reg;
}

이러한 포인터가로 표시되지 않은 경우 volatile몇 가지 문제가 발생할 수 있습니다.

  • while 루프 테스트는 상태 레지스터를 한 번만 읽을 수 있습니다. 컴파일러는 지시 한 내용이 변경되지 않을 것이라고 가정 할 수 있기 때문입니다 (while 루프 테스트 또는 루프 자체에는 변경할 수있는 항목이 없습니다). UART 하드웨어에서 대기중인 문자가 없을 때 기능을 입력하면 문자를 수신해도 멈추지 않는 무한 루프에 빠질 수 있습니다.
  • 수신 레지스터의 읽기는 컴파일러에 의해 while 루프 이전으로 이동할 수 있습니다 *recv_reg. 루프에 의해 변경 되었음을 나타내는 함수가 없기 때문에 루프에 들어가기 전에 읽을 수없는 이유가 없습니다.

volatile예선 보장하지만 이러한 최적화는 컴파일러에 의해 수행되지 않습니다.


5
설명은 +1. 그리고 질문이 있습니다. const volatile 메서드는 어떻습니까? 많은 스레드에서 액세스하는 클래스가있는 경우 (액세스는 뮤텍스와 동기화되지만) 내 const 메서드도 휘발성이어야합니까 (일부 변수는 다른 스레드에 의해 변경 될 수 있기 때문)
Sasa

39
  • volatile 일반적으로 다른 스레드에 의해 "외부"에서 변경 될 수 있음을 알고있을 때 변수와 관련된 코드를 최적화하지 않도록 컴파일러에 지시합니다.
  • const 프로그램이 변수 값을 수정하는 것이 금지되어 있음을 컴파일러에 알립니다.
  • const volatile당신의 인생에서 정확히 0 번 사용되는 것을 보게 될 매우 특별한 것입니다 (tm). 예상대로 프로그램이 변수의 값을 수정할 수 없지만 외부에서 값을 수정할 수 있으므로 변수에 대한 최적화가 수행되지 않음을 의미합니다.

12
나는 volatile변수가 일반적으로 다른 스레드가 아닌 하드웨어를 망칠 때 발생하는 일 이라고 생각했습니다 . 내가 const volatile사용한 곳은 메모리 매핑 상태 레지스터 등과 같은 것입니다.
그냥 내 올바른 의견

2
물론, 당신 말이 맞습니다. 멀티 스레딩은 하나의 예일뿐입니다. :).
mingos 2011 년

25
임베디드 시스템으로 작업하는 경우 자주 볼 수 있습니다.
Daniel Grillo

28

변수가 const이기 때문에 두 시퀀스 포인트 사이에서 변경되지 않았을 수도 있습니다.

Constness는 값을 변경하지 않겠다는 약속이지 값이 변경되지 않을 것이라는 약속입니다.


9
const데이터가 "상수"가 아님 을 지적하기위한 하나입니다 .
Bogdan Alexandru

7

일부 구성 변수가 부트 로더에 의해 업데이트 될 수있는 플래시 메모리 영역에있는 임베디드 애플리케이션에서이를 사용해야했습니다. 이러한 구성 변수는 런타임 동안 '상수'이지만 휘발성 한정자가 없으면 컴파일러는 다음과 같이 최적화합니다.

cantx.id = 0x10<<24 | CANID<<12 | 0;

... 상수 값을 미리 계산하고 즉각적인 어셈블리 명령을 사용하거나 근처 위치에서 상수를로드하여 구성 플래시 영역의 원래 CANID 값에 대한 모든 업데이트가 무시됩니다. CANID는 const 휘발성이어야합니다.


7

C에서 const와 volatile은 유형 한정자이며이 두 가지는 독립적입니다.

기본적으로 const는 프로그램에서 값을 수정할 수 없음을 의미합니다.

휘발성은 값이 갑작스럽게 변경 될 수 있음을 의미합니다 (프로그램 외부에서 가능).

실제로 C 표준은 const와 volatile 인 유효한 선언의 예를 언급합니다. 예는

"extern const volatile int real_time_clock;"

여기서 real_time_clock은 하드웨어에 의해 수정 가능하지만 할당, 증가 또는 감소 할 수 없습니다.

따라서 우리는 이미 const와 volatile을 별도로 처리해야합니다. 게다가, 이러한 유형 한정자는 struct, union, enum 및 typedef에도 적용됩니다.


5

const와 volatile을 함께 사용할 수 있습니다. 예를 들어 0x30이 외부 조건에 의해서만 변경되는 포트의 값으로 간주되는 경우 다음 선언은 우발적 인 부작용 가능성을 방지합니다.

const volatile char *port = (const volatile char *)0x30;

4

const변수는 c 코드로 수정할 수 없으며 변경할 수 없음을 의미합니다. 이는 명령어가 변수에 쓸 수 없지만 그 값은 여전히 ​​변경 될 수 있음을 의미합니다.

volatile변수가 언제든지 변경 될 수 있으므로 캐시 된 값을 사용할 수 없음을 의미합니다. 변수에 대한 각 액세스는 해당 메모리 주소에 대해 실행되어야합니다.

질문에 "embedded"태그가 지정되어 있고 temp 되고 하드웨어 관련 레지스터가 아니라 사용자 선언 변수라고 하므로 (일반적으로 별도의 .h 파일에서 처리되므로) 다음을 고려하십시오.

휘발성 읽기-쓰기 데이터 메모리 (RAM)와 비 휘발성 읽기 전용 데이터 메모리 (예 : 데이터와 프로그램 공간이 공통 데이터 및 주소 버스를 공유하는 von-Neumann 아키텍처의 FLASH 메모리)를 모두 포함하는 임베디드 프로세서.

선언하면 const temp 하면 (적어도 0과 다른 경우) 컴파일러는 변수를 FLASH 공간의 주소에 할당합니다. RAM 주소에 할당 되었더라도 초기 값을 저장하려면 여전히 FLASH 메모리가 필요하기 때문입니다. 모든 작업이 읽기 전용이기 때문에 RAM 주소를 공간 낭비로 만듭니다.

결과적으로 :

int temp;RAM에 저장된 변수이며 시작시 (cstart) 0으로 초기화되며 캐시 된 값을 사용할 수 있습니다.

const int temp;(read-ony) FLASH에 저장된 변수이며 컴파일러 시간에 0으로 초기화되며 캐시 된 값을 사용할 수 있습니다.

volatile int temp; RAM에 저장된 변수이며 시작시 0으로 초기화 (cstart), 캐시 된 값은 사용되지 않습니다.

const volatile int temp; (read-ony) FLASH에 저장된 변수이며 컴파일러 시간에 0으로 초기화되며 캐시 된 값은 사용되지 않습니다.

다음은 유용한 부분입니다.

오늘날 대부분의 임베디드 프로세서는 특수 기능 모듈을 통해 읽기 전용 비 휘발성 메모리를 const int temp변경할 수 있습니다. 이 경우 런타임시 변경할 수 있지만 직접 변경할 수는 없습니다. 즉, 함수 temp는 저장된 주소의 값을 수정할 수 있습니다 .

실용적인 예는 temp장치 일련 번호 를 사용 하는 것 입니다. 임베디드 프로세서가 처음 실행될 때 temp0 (또는 선언 된 값)과 같으며 함수는이 사실을 사용하여 생산 중에 테스트를 실행할 수 있으며 성공하면 일련 번호 할당을 요청하고 값을 수정합니다.temp 의한을 특별한 기능의. 일부 프로세서에는 OTP (일회성 프로그래밍 가능) 메모리가있는 특수 주소 범위가 있습니다.

그러나 여기에 차이점이 있습니다.

경우 const int temp대신 한 번 프로그래밍 일련 번호의 수정 ID이고 선언되지 않습니다 volatile, 캐시 값은 새 ID가 전까지 다음 재부팅, 또는 더 나쁜, 일부 기능이 유효하지 않을 수 있습니다 의미, 다음 부팅 전까지 사용할 수 있습니다 다른 사람은 재부팅 할 때까지 이전 캐시 된 값을 사용하는 동안 새 값을 사용할 수 있습니다. 경우 const int tempIS 선언 voltaile의 ID 변경은 즉시 적용한다.




2

간단히 말해서 'const volatile'변수의 값은 프로그래밍 방식으로 수정할 수 없지만 하드웨어로 수정할 수 있습니다. 여기서 휘발성은 컴파일러 최적화를 방지하는 것입니다.


1

프로그램이 변경하는 것을 원하지 않을 때 변수에 'const'키워드를 사용합니다. 변수 'const volatile'을 선언 할 때 우리는 프로그램과 컴파일러에게이 변수가 외부 세계에서 들어오는 입력으로 인해 예기치 않게 변경 될 수 있음을 알려줍니다.

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