많은 저수준 프로그램은 메모리 매핑과 같은 유형에 volatile 키워드를 사용하지만 배경에서 실제로 하는 일에 대해서는 혼란 스럽습니다 . 다시 말해, 컴파일러가 메모리 주소를 "최적화"하지 않을 때의 의미는 무엇입니까?
많은 저수준 프로그램은 메모리 매핑과 같은 유형에 volatile 키워드를 사용하지만 배경에서 실제로 하는 일에 대해서는 혼란 스럽습니다 . 다시 말해, 컴파일러가 메모리 주소를 "최적화"하지 않을 때의 의미는 무엇입니까?
답변:
volatile
다른 프로세서 또는 I / O 장치 또는 무언가가 변수를 변경할 수 있음을 의미합니다.
일반적인 변수를 사용하면 프로그램 단계 만 변경됩니다. 예를 들어 5
변수 를 읽고 변경하지 않으면 여전히을 포함합니다 5
. 그것에 의존 할 수 있기 때문에 프로그램은 다음에 변수를 사용할 때 변수를 다시 읽는 데 시간을 들일 필요가 없습니다. C ++ 컴파일러는을 기억하는 코드를 생성하는 것이 현명합니다 5
.
그러나로 읽을 수 있으면 5
시스템이 디스크에서 해당 메모리로 데이터를로드하여로 변경합니다 500
. 프로그램이 새로운 값을 읽도록 500
하려면 이전에 읽은 사용에 대해 너무 똑똑하지 않은 컴파일러가 필요합니다 5
. 매번 값을 다시로드하도록 지시해야합니다. 그게 뭐야 volatile
.
5 살짜리 아이들의 비유
큰 종이를 테이블 위에 올려 놓았다고 가정 해 봅시다. 논문의 한 구석에 진행중인 게임의 현재 점수를 기록합니다 3 to 4
. 그런 다음 테이블 반대편으로 가서 게임에 대한 이야기를 쓰기 시작합니다. 게임을보고있는 친구가 게임이 진행됨에 따라 해당 코너의 점수를 업데이트합니다. 그녀는 지우고 3 to 4
씁니다 3 to 5
.
게임 점수를 스토리에 넣으면 다음 중 하나를 수행 할 수 있습니다.
3 to 4
변경하지 않았다고 가정하거나 적어 두십시오.3 to 5
걸어가십시오. 이것이 volatile
변수의 작동 방식입니다.volatile
두 가지 의미 :
변수 값은 코드를 변경하지 않고 변경 될 수 있습니다. 따라서 컴파일러가 변수 값을 읽을 때마다 변수를 마지막으로 읽은 시간과 같거나 마지막으로 저장된 값과 같다고 가정 할 수 없지만 다시 읽어야합니다.
휘발성 변수에 값을 저장하는 행위는 외부에서 관찰 될 수있는 "부작용"이므로 컴파일러는 값을 저장하는 행위를 제거 할 수 없습니다. 예를 들어 두 개의 값이 한 행에 저장된 경우 컴파일러는 실제로 값을 두 번 저장해야합니다.
예로서:
i = 2;
i = i;
컴파일러 는 숫자 2를 저장하고 변수 i를 읽고 읽은 변수를 i에 저장해야합니다.
또 다른 상황이 있습니다. 함수가 사용 setjmp
하고 longjmp
호출되면 함수의 모든 휘발성 로컬 변수는 마지막 값이 저장되도록 보장됩니다. 이는 비 휘발성 로컬 변수의 경우에는 해당되지 않습니다.
i
와 값을 pi = &i
다음 x = *pi
에서 읽기를 수행 i
하지만 읽기는 휘발성 의미가 보장되지 않습니다.
i
같은 선언 volatile int i
다음 pi
과 같이 선언해야 volatile int *pi
하는 경우에, *pi
아니, 휘발성 액세스입니까?
추상 설명
C와 C ++는 모두 추상 기계 라는 개념을 가지고 있습니다 . 코드가 일부 변수의 값을 사용할 때 추상 기계는 구현에서 해당 변수의 값에 액세스해야한다고 말합니다. 양식의 코드는 statement_A; statement_B; statement_C;
지정된 순서대로 실행해야합니다. 이 세 가지 진술에 공통적 인 표현은 발생할 때마다 다시 계산해야합니다.
추상 머신에 따라, 일련의 명령문이 주어지면 statement_A; statement_B; statement_C;
구현은 먼저 statement_A
전체를 수행 한 다음 statement_B
마지막으로 수행해야합니다 statement_C
. 구현시 age
5 값을 할당했음을 기억할 수 없습니다 . 참조하는 모든 명령문 age
은 대신 해당 변수의 값에 액세스해야합니다.
volatile
추상 시스템 사양에 따라 구현에서 C 또는 C ++ 코드를 엄격하게 실행하는 경우 키워드 가 필요하지 않습니다 . C 및 C ++ 추상 머신에는 레지스터 개념이없고 공통 하위 표현식 개념이 없으며 실행 순서가 엄격합니다.
두 언어 모두 as-if 규칙이 있습니다. 구현은 추상 시스템 사양에 따라 작업을 실행 한 것처럼 동작하는 한 표준을 준수 합니다. 컴파일러는 비 휘발성 변수가 할당간에 값을 변경하지 않는다고 가정 할 수 있습니다. as-if
규칙을 어 기지 않는 한 , statement_A; statement_B; statement_C;
일부 statement_C
, 일부 statement_A
, 전체 statement_B
, 나머지 statement_A
및 마지막으로 나머지를 실행 하여 시퀀스를 구현할 수 있습니다 statement_C
.
이러한 as-if 규칙은 volatile
변수에 적용되지 않습니다 . volatile
변수와 함수 와 관련하여 구현은 사용자가 지시 한대로 정확하게 수행해야합니다.
추상 기계 사양에는 단점이 있습니다. 느립니다. 다른 언어에 비해 C 및 C ++의 한 가지 긍정적 인 측면은 언어가 매우 빠르다는 것입니다. 이러한 추상 시스템마다 코드가 실행 된 경우에는 그렇지 않습니다. 로-경우 규칙은 C 및 C ++ 너무 빨리 될 수 있도록 무엇인가.
ELI5 답변
컴파일러가 메모리 주소를 "최적화"하지 않을 때의 의미는 무엇입니까?
메모리 주소 "최적화"는 고급 개념으로 5 살짜리 기능의 영역에 속하지 않습니다. 준수하는 다섯 살짜리 아이들은 더 이상, 더 이상,하지 말라고 정확하게 행동 할 것입니다. 을 사용 volatile
하면 구현이 5와 같이 작동하도록 지시합니다. 생각하지 않고 멋진 최적화가 없습니다. 대신 구현시 코드에서 지시 한대로 정확하게 수행해야합니다.
(비) 휘발성은 컴파일러가 생성 한 어셈블리 코드 관점에서 코드를 최적화하는 방법에 대한 힌트입니다.
대답은 꽤 일관성이 있지만 중요한 요점이 없습니다. 컴파일러에게 공간을 할당하고 모든 액세스에 대해 읽기 또는 쓰기를 읽고 해당 액세스를 수행하길 원한다고 알려주고 있습니다. 우리는 어떤 이유로 액세스 또는 변수를 최적화하는 것을 원하지 않습니다.
그렇습니다. 다른 사람이 우리를 위해 그 가치를 바꿀 수 있기 때문입니다. 또 다른 이유는 우리가 다른 사람을 위해 그 가치를 바꿀 수 있기 때문입니다. 다른 사람이 우리를 위해 그것을 바꾸거나 다른 사람이 하드웨어 / 논리 또는 소프트웨어 일 수 있습니다. 베어 메탈 임베디드 프로그램에서 하드웨어에 쓰거나 읽을 때 제어 및 상태 레지스터에 대한 액세스를 정의하는 데 종종 사용됩니다. 소프트웨어와 대화하는 소프트웨어뿐만 아니라 다른 답변에서 설명했습니다.
또한 코드 섹션의 시간을 정하려고 할 때 액세스가 언제, 어떤 순서로 액세스되는지 제어하는 데 휘발성이 사용되는 것을 볼 수 있으며 문제의 변수 (시작 시간, 종료 시간 및 차이) 만 휘발성을 사용하지 않아야합니다. 컴파일러는 끝 부분 근처에서 계산되어 시간 측정 중 하나를 자유롭게 이동할 수 있습니다 (우리가 배치 한 위치가 아니라).
때때로, 당신은 단순히 시간을 태우는 데 사용되는 것을 보게 될 것입니다. 맨발의 야광 세계 인 초등 led 깜박임은 인간의 눈이 led를 볼 수있는 시간을 태우기 위해 변수에 휘발성을 사용할 수 있습니다. 상태를 변경하십시오. 타이머 나 다른 이벤트를 사용하여 시간을 소모하는 고급 예제
volatile
변수에서 나이를 읽고 5라고 말하고 내년에 다시 읽으면 6을 얻습니다.