쓰기 전용 포인터 유형
임베디드 시스템용 소프트웨어를 만들고 있습니다.
포인터를 사용하여 FPGA 디바이스의 레지스터에 액세스하고 있습니다.
일부 레지스터는 읽기 전용이고 다른 레지스터는 쓰기 전용입니다.
읽기 전용 레지스터는 읽을 때 정의되지 않은 값을 생성합니다.
컴파일러가 쓰기 전용 레지스터에서 값을 읽을 때 탐지할 수 있는 포인터 유형을 정의합니다(예: 참조).
C 언어 구문만 사용하여 쓰기 전용 포인터를 만들 수 있습니까?
(C를 사용하여 1차 시제품을 개발 중이지만, 2세대부터는 C++로 이행합니다.)
C++에서 효율적인 쓰기 전용 포인터를 작성하려면 어떻게 해야 합니까?(이것은 동적 메모리 내의 항목을 추적하는 것이 아니라 하드웨어 주소에 액세스하는 것입니다).
이 코드는 안전과 품질이 가장 중요한 임베디드 시스템에서 사용됩니다.
아마 각각에 대해 작은 래퍼 클래스를 작성할 것입니다.
template <class T>
class read_only {
T volatile *addr;
public:
read_only(int address) : addr((T *)address) {}
operator T() volatile const { return *addr; }
};
template <class T>
class write_only {
T volatile *addr;
public:
write_only(int address) : addr ((T *)address) {}
// chaining not allowed since it's write only.
void operator=(T const &t) volatile { *addr = t; }
};
적어도 당신의 시스템이 합리적인 컴파일러를 가지고 있다고 가정한다면, 나는 이 두 가지 모두를 최적화해서 생성된 코드를 원시 포인터와 구별할 수 없을 것이라고 예상한다.사용방법:
read_only<unsigned char> x(0x1234);
write_only<unsigned char> y(0x1235);
y = x + 1; // No problem
x = y; // won't compile
저는 많은 하드웨어로 작업해 왔습니다만, 그 중 일부는 "읽기 전용" 또는 "쓰기 전용" 레지스터(또는 레지스터에 읽기 또는 쓰기 여부에 따라 다른 함수)를 가지고 있습니다.이러한 함수는 누군가가 값을 기억하는 대신 "reg |= 4;"를 실행하기로 결정했을 때 재미를 줍니다. 비트 2를 설정하고 새 값을 씁니다.판독할 수 없는 레지스터에서 랜덤 비트가 표시되거나 표시되지 않는 하드웨어를 디버깅하는 것 같은 것은 없습니다!) 지금까지 쓰기 전용 레지스터로부터의 읽기나 읽기 전용 레지스터에의 쓰기를 실제로 차단하는 시도는 본 적이 없습니다.
덧붙여서, 「쓰기 전용」의 레지스터를 가지는 것은 정말로 나쁜 생각입니다.왜냐하면 소프트웨어가 레지스터를 올바르게 설정했는지 확인하기 위해서 판독을 할 수 없기 때문에, 디버깅이 매우 어려워집니다.드라이버를 쓰는 사람은 VHDL 또는 Verilog 코드의 2행으로 간단하게 할 수 있는 어려운 문제를 디버깅하는 것을 좋아하지 않기 때문입니다.
레지스터 레이아웃을 어느 정도 제어할 수 있다면, 4KB로 정렬된 주소에 "읽기 전용" 레지스터를 배치하고 다른 4KB로 정렬된 주소에 "쓰기 전용" 레지스터를 배치하는 것이 좋습니다.그런 다음 접근을 방지하도록 하드웨어의 메모리 컨트롤러를 프로그래밍할 수 있습니다.
또는 읽으면 안 되는 레지스터가 읽혀지거나 쓰이면 안 되는 레지스터가 쓰여지면 하드웨어가 인터럽트를 발생시킵니다.하드웨어는 다른 목적으로 인터럽트를 발생시키나요?
다양한 C++ 솔루션을 사용하는 다른 제안도 괜찮지만, 레지스터를 직접 사용하는 것을 꺼리는 것은 아니기 때문에 ('어색하게 하자'가 아니라) 정말 안전상의 문제라면 하드웨어 오용으로부터 보호할 수 있는 하드웨어가 필요합니다.
레지스터를 복원하기 위한 구조와 그것들을 처리하기 위한 함수 쌍을 조합하여 사용합니다.
①의 fpga_register.h
거 요.
#define FPGA_READ = 1;
#define FPGA_WRITE = 2;
typedef struct register_t {
char permissions;
} FPGARegister;
FPGARegister* fpga_init(void* address, char permissions);
int fpga_write(FPGARegister* register, void* value);
int fpga_read(FPGARegister* register, void* value);
또는 xor에서 READ 및 WRITE를 사용하여 권한을 표현합니다.
서서 the fpga_register.c
합니다.
typedef struct register_t2 {
char permissions;
void * address;
} FPGARegisterReal;
.FPGARegister
fpga_init
.
러......에...fpga_read
★★★★★★★★★★★★★★★★★」fpga_write
하고 ""를 선택합니다.
- 수 있습니다.
FPGARegister
FPGARegisterReal
액션을하여 성공 인 "Success Code"를 - 작업이 허용되지 않으면 오류 코드를 반환합니다.
하면 한 어느 도 ""에 수 .FPGARegisterReal
따라서 레지스터 주소에 직접 액세스할 수 없습니다.물론 해킹도 가능하겠지만, 그런 고의적인 해킹은 당신의 실제 관심사가 아니라고 확신합니다.
C에서는 불완전한 유형에 대한 포인터를 사용하여 모든 비참조를 방지할 수 있습니다.
/* writeonly.h */
typedef struct writeonly *wo_ptr_t;
/* writeonly.c */
#include "writeonly.h"
struct writeonly {
int value
};
/*...*/
FOO_REGISTER->value = 42;
/* someother.c */
#include "writeonly.h"
/*...*/
int x = FOO_REGISTER->value; /* error: deref'ing pointer to incomplete type */
만.writeonly.c
가 「」인 struct writeonly
는 포인터를 참조 해제할 수 있습니다.물론 이 코드도 실수로 값을 읽을 수 있지만 적어도 다른 모든 코드는 포인터를 모두 참조하는 것을 방지하고 포인터를 전달하여 변수, 배열 및 구조에 저장할 수 있습니다.
writeonly.[ch]
을 사용하다
C에서는 우아한 방법이 보이지 않는다.하지만 방법이 있을 것 같습니다.
#define DEREF_PTR(type, ptr) type ptr; \
typedef char ptr ## _DEREF_PTR;
#define NO_DEREF_PTR(type, ptr) type ptr; \
#define DEREFERENCE(ptr) \
*ptr; \
{ptr ## _DEREF_PTR \
attempt_to_dereference_pointer_ ## ptr;}
int main(int argc, char *argv[]) {
DEREF_PTR(int*, x)
NO_DEREF_PTR(int*, y);
DEREFERENCE(x);
DEREFERENCE(y); // will throw an error
}
이를 통해 정적 오류를 확인할 수 있습니다.물론 이 방법을 사용하면 매크로를 사용하기 위해 포인터 선언을 모두 수정해야 합니다.이것은 그다지 즐겁지 않을 것입니다.
편집: 댓글에 기재되어 있는 바와 같습니다.
#define READABLE_PTR(type, ptr) type ptr; \
typedef char ptr ## _READABLE_PTR;
#define NON_READABLE_PTR(type, ptr) type ptr; \
#define GET(ptr) \
*ptr; \
{ptr ## _READABLE_PTR \
attempt_to_dereference_non_readable_pointer_ ## ptr;}
#define SET(ptr, value) \
*ptr = value;
int main(int argc, char *argv[]) {
READABLE_PTR(int*, x)
NON_READABLE_PTR(int*, y);
SET(x, 1);
SET(y, 1);
int foo = GET(x);
int bar = GET(y); // error
}
Dan Saks가 Youtube 프레젠테이션을 하는데, 임베디드 기기용 쓰기 전용 레지스터를 어디서 도입하는지 찾을 수 없었습니다.
다행히 그는 검색하기 쉬운 기사를 https://www.embedded.com/how-to-enforce-write-only-access/에 썼다.
이것은 C++11용으로 갱신된 기사의 코드입니다.
class write_only_T{
public:
write_only_T(){}
write_only_T(T const& v) : m(v){}
write_only_T(T&& v) : m(std::move(v)){}
write_only_T& operator=(T const& v){
m = v;
return *this;
}
write_only_T& operator=(T&& v){
m = std::move(v);
return *this;
}
write_only_T(write_only_T const&) = delete;
write_only_T(write_only_T&&) = delete;
write_only_T& operator=(write_only_T const&) = delete;
write_only_T& operator=(write_only_T&&) = delete;
private:
T m;
};
쓰기 전용이 값의 속성이기 때문에 이것을 사용했다면 특별한 포인터 타입은 필요 없다고 생각합니다만, 값 타입을 건너뛰는 합성 포인터 타입은 상상할 수 있습니다.기입 전용 레퍼런스 타입 등을 도입할 필요가 있을 가능성이 있습니다.
언급URL : https://stackoverflow.com/questions/16049329/write-only-pointer-type
'programing' 카테고리의 다른 글
Vue.js 3 - Vue 컴포넌트 간에 데이터를 전달하고 두 뷰 모두 업데이트하려면 어떻게 해야 합니까? (0) | 2022.08.13 |
---|---|
Vuex는 내부 첫 번째 행의 버튼을 클릭할 때만 컴포넌트를 갱신합니다. (0) | 2022.08.13 |
Vue.js 2, WATCH "워처 "Your AccountState" 콜백 오류: "ReferenceError: 값이 정의되지 않았습니다." (0) | 2022.08.13 |
형식 스크립트가 포함된 Vuex 4를 사용하는 유형 'ComponentPublicInstance'에 속성 '$store'가 없습니다. (0) | 2022.08.13 |
함수 이름 주위의 괄호는 무엇을 의미합니까? (0) | 2022.08.13 |