포인터가 일정하고 휘발성이 있다고 선언되었습니다.
책을 읽다가 이런 종류의 선언문을 발견했는데, 다음과 같은 구절을 발견했습니다.
const volatile char *p=(const volatile char *) 0x30;
p 값은 외부 조건에 의해서만 변경됩니다.
외부 조건이 뭔지 모르겠어요.그리고 이런 유형의 선언이 실용적으로 무슨 소용이 있겠는가?
그 그const
프로그램의 흐름이프로그램 흐름으로 인해 에 의해 지적된 내용이 변경되지 않는다고 합니다로 인식은 수정하지 않을 것이다 말한다.p
. 어떤 시도도 포인터는 컴파일 타임 오류로 이어질 것이다 역 참조 후 값을 수정할:.포인터를 참조 해제한 후 값을 변경하려고 하면 컴파일 시 오류가 발생합니다.
*p = 'A'; // will not compile
도 아니고 특별히 강한 계약, 위치에서 값 이 계약은 특별히 강력한 계약이라고 할 수 없습니다습니다.로케이션에서의 가치는0x30
아직도 시non-const 포인터를 통해, 에일리어싱부정수 포인터를 통해 변경할수 있습니다보다 다른이 바뀔 수 있을까.p
:
volatile char *q = 0x30;
*q = 'A'; // will compile
또 다른 방법 이 계약을 파기할 파기하는 또 다른 방법은 이 계약을 파기하는 것입니다는 이 계약을을 주조에 있다.const
부터에서p
:
*(volatile char *) p = 'A'; // will compile
그 그volatile
그러나 다른 스레드는 커널, 비동기 신호 처리기 또는 이와 같은 메모리 공간에 접근할 수 있어 외부 장치에 의해 발생할 수 있는 어떤 수정을 제외하지 않는다.단,다른 스레드, 커널, 비동기 신호 핸들러 또는 동일한 메모리 공간에 액세스할 수 있는 외부 장치에 의해 발생할 수 있는 변경은 제외되지 않습니다.컴파일러는 잘못된 가정은 값으로이렇게 하면이 가리키게 할 수 없다 이런 식으로 컴파일러는 값이 가리키는 잘못된 가정을 할 수 없습니다.p
그리고 기억에서 참조되는 모든 시간:는 변경되지않고 참조될 때마다메모리에서 로딩됩니다 로드를 바꾸지 않나.
/*
The character at 0x30 will be read on every iteration,
even if the compiler has proven that the program itself
doesn't modify the value at that address.
*/
while (*p) {
...
}
컴파일러가 이러한 구성을 잘못 최적화하면 메모리로부터 값을 한 번만 로드한 후 레지스터에 저장하는 명령을 내보낼 수 있습니다.레지스터는 기본적으로 독립된 복사본이며 원래 위치에 대한 변경은 반영되지 않습니다. 말할 필요도 없이, 이것은 매우 불쾌한 버그를 일으킬 수 있습니다.
예를 들어 네트워크 카드의 읽기 전용 하드웨어 레지스터를 생각해 보겠습니다.
그래서 컴파일러를 명부에 있든지, 최대화하게 값을 캐시 하는 데 허용되지 않아 프로그램의 통제 바깥에, 바뀔 수 있습니다.프로그램 제어 밖에서 변경될 수 있으므로 컴파일러는 레지스터에 값을 캐시하거나 최적화할 수 없습니다.thus따는volatile
.
그리고 읽기 전용이므로, 여기에 쓰면 안 됩니다.thus따는const
.
먼저, 예를 들어보겠습니다.C11
표준, 제6.7.3장, 형식 한정자
선언된 객체
extern const volatile int real_time_clock;
는 하드웨어로 변경할 수 있지만 할당, 증가 또는 감소는 할 수 없습니다.
또한 관련 각주(134),
휘발성 선언은 메모리 매핑된 입출력 포트에 대응하는 오브젝트 또는 비동기 인터럽트 함수에 의해 액세스되는 오브젝트를 기술하기 위해 사용될 수 있다.이렇게 선언된 객체에 대한 액션은 표현 평가 규칙에 의해 허용된 경우를 제외하고 구현에 의해 "최적화"되거나 순서를 변경할 수 없습니다.
즉, 변수 값은 (메모리 매핑을 통해) 하드웨어에 의해 수정될 수 있지만 "프로그램적으로" 수정할 수는 없습니다.
여기서 장점은 두 가지입니다.
- 값이 사용될 때마다 메모리에서 읽혀지고(캐시 입력이 허용되지 않음), 업데이트된 최신 값이 제공됩니다(업데이트된 경우).
- 이 값은 프로그램에 의해 의도적으로 또는 의도하지 않게 변경(쓰기)될 수 있음).
「Introduction to volatile keyword」라고 하는 기사를 사용할 수 있습니다.
변수는 값이 예기치 않게 변경될 수 있는 경우 항상 volatile로 선언해야 합니다.실제로 변경할 수 있는 변수는 다음 세 가지 유형뿐입니다.
- 메모리 매핑된 주변기기 레지스터
- 인터럽트 서비스 루틴에 의해 수정된 글로벌 변수
- 멀티 스레드 응용 프로그램 내 글로벌 변수
또, 다음과 같이 합니다.
임베디드 시스템에는 보통 고도의 주변기기를 갖춘 실제 하드웨어가 포함되어 있습니다.이들 주변기기에는 프로그램흐름에 비동기적으로 값이 변경될 수 있는 레지스터가 포함되어 있습니다.매우 간단한 예로서 주소 0x1234의 8비트 상태 레지스터를 생각해 보겠습니다.상태 레지스터가 0이 아닐 때까지 폴링해야 합니다.잘못된 실장은 다음과 같습니다.
UINT1 * ptr = (UINT1 *) 0x1234; // Wait for register to become non-zero. while (*ptr == 0); // Do something else.
컴파일러는 다음과 같은 어셈블리 언어를 생성하기 때문에 옵티마이저를 켜면 바로 실패합니다.
mov ptr, #0x1234 mov a, @ptr loop bz loop
Const는 프로그램이 변수를 변경하지 않지만 외부 소스 기사에서 언급한 바와 같이 변수가 최적화되지 않도록 할 수 있다고 말합니다.
*const volatile char *p=(const volatile char) 0x30;
의미:p 값은 외부 조건에 의해서만 변경됩니다.
개념적으로는 이 유형의 변수를 논리 뷰어로 생각할 수 있습니다.문틈에 뚫린 구멍과 비슷한 개념입니다.문의 반대편에 있는 것은 볼 수 있지만 반대편에 있는 것은 변경할 수 없습니다(계속).단, 도어 외부의 조건은 임의로 변경될 수 있습니다(변동성이 있습니다).무슨 일이 일어나는지 볼 수는 있지만, 무슨 일이 일어나는지 바꿀 수는 없습니다.
예를 들어 임베디드 시스템에는 외부에서 발생하는 이벤트에 대한 상태 정보를 제공하도록 설계된 하드웨어 레지스터가 있습니다.예를 들어 RPM을 검출하기 위해 사용되는 광학 인코더는 레지스터에 값을 설정합니다.회전할 때마다 LED의 빛을 감지하고 하드웨어 레지스터의 값을 변경합니다.이것이 외부 조건의 의미입니다.그림 반대편, 즉 코드(PID 제어 루프)에서는 이 정보를 읽고 루프를 조정하는 데 사용할 수 있지만 이 값을 변경할 수도 없고 변경할 수도 없습니다.
소프트웨어의 관점에서 보면, 이것은 다음과 같은 것을 나타내고 있습니다.
const
변수를 상수로 만들지 않습니다.컴파일러가 쓰기 액세스를 거부하게 만들 뿐입니다.이것은 (예를 들어 연속 캐스트된 포인터를 통해) 변수에 쓸 수 있습니다.
보이시죠?const
코딩 실수로부터 보호하기 위해서입니다.
이 선언을 통해 부주의로 다음 주소로 편지를 쓰지 않도록 합니다.p
외부 이벤트가 기록될 수 있으므로 액세스(캐시, 순서가 잘못된 실행(?))을 최적화하지 않도록 컴파일러에 지시합니다.p
.
언급URL : https://stackoverflow.com/questions/31456274/pointer-declared-as-constant-as-well-as-volatile
'programing' 카테고리의 다른 글
C++에서 CMake가 링커 언어를 판별할 수 없음 (0) | 2022.06.30 |
---|---|
VueJ에서의 번호 포맷 방법s (0) | 2022.06.30 |
로드 시 Vue.js v-if 및 v-f를 포함하는 HTML 태그 (0) | 2022.06.29 |
gcc에서 컴파일러 최적화를 비활성화하는 방법 (0) | 2022.06.29 |
지역 의존 해시를 이해하려면 어떻게 해야 하나요? (0) | 2022.06.29 |