목록전체 글 (18)
Sonji-log
정의HIL(Hardware-in-the-Loop)은 실제 Hardware DUT(Device Under Test)를 Test Loop 안에 두고, DUT와 연결되는 외부 환경이나 장치 일부를 제어 가능한 System으로 대신하는 방식이다. 현재 회사 프로젝트에서는 STM32가 UART로 외부 농도 Sensor를 읽는다. 이때 실제 Hardware DUT는 STM32이고, PC가 Project에서 사용하는 DS4/TB200B Sensor를 대신하도록 구성했다.STM32 Request→ PC Fake Sensor→ UART Response→ STM32 Parser/Application→ DUT Status→ PC Matcher마지막 DUT Status가 다시 PC로 돌아오기 때문에 Loop가 닫힌다.일반 S..
만들게 된 이유하드웨어 개발에서 가장 큰 스트레스는 정상 동작하는 실물이 있어야 개발 및 테스트가 제대로 진행된다는 점이다.심지어 모든 실물이 갖추어져 있다고 하더라도, 정말 예상치 못한 부분에서 문제가 언제 어떻게 터질 지 모른다는 점도 마찬가지다.가뜩이나 AI 코딩의 생산성이 어마어마한 지금, 이런 병목을 가만 둘 수가 없었다.그래서, 간략하게나마 "모든 하드웨어가 정상적으로 동작한다고 가정할 때, 통신 혹은 알고리즘 등의 원활한 개발을 위해" 센서를 모사하는 에뮬레이터를 만들어보기로 했다. 회사에서 진행하는 Embedded Project에는 STM32가 UART로 외부 농도 Sensor 값을 읽는 기능이 있다. 실제 제품의 세부 내용보다는, Sensor Request와 Response를 처리하는 F..
1. 이 항목이 왜 중요한가소멸자(destructor)는 객체의 마지막 정리 담당자다. 메모리를 해제하고, 파일을 닫고, mutex를 풀고, 데이터베이스 연결을 종료한다. 앞서 Cp 7.에서 소멸자가 제대로 호출되는지가 중요하다고 봤다면, 이번에는 호출된 소멸자가 어떤 식으로 끝나야 하는가를 다룬다.겉보기에는 이런 코드가 자연스럽다.class DBConnection{public: static DBConnection create(); void close(); // 실패하면 예외를 던질 수 있다};class DBConn{public: explicit DBConn(const DBConnection& connection) : db(connection) {} ~DBConn..
1. 이 항목이 왜 중요한가C++에서는 기본 클래스(base class) 포인터로 파생 클래스(derived class) 객체를 다루는 일이 아주 흔하다. 다형성(polymorphism)을 쓰는 코드라면 거의 항상 이런 형태가 나온다.Base* p = new Derived();// ...delete p;겉보기에는 꽤 자연스럽지만, 여기에는 함정이 하나 숨어 있다.만약 Base의 소멸자가 가상 함수(virtual function)가 아니라면, delete p를 했을 때 무슨 일이 벌어질까?결론부터 말하면 정의되지 않은 동작(undefined behavior)이 수행된다. 보통은 다음과 같은 일이 일어난다.객체의 기본 클래스 부분(Base)은 소멸된다.하지만 파생 클래스 부분(Derived)은 소멸되지 않는..
1. 이 항목이 왜 중요한가C++에서는 내가 직접 쓰지 않아도 컴파일러가 몇몇 함수를 자동으로 만들어 주는 경우가 있다. 대표적으로 아래 두 가지가 자주 문제를 만든다.복사 생성자(copy constructor)복사 대입 연산자(copy assignment operator)겉으로 보기에는 편리하다. 하지만 어떤 클래스는 "복사되면 안 되는 객체" 인데도, 아무 조치를 하지 않으면 복사가 가능해질 수 있다.예를 들어, 아래와 같은 경우를 생각해 보자.mutex 같은 동기화 객체파일 핸들, 소켓 핸들 같은 시스템 자원"오직 하나만 존재해야 하는" 객체(Singleton Pattern에 해당하는 성격의 객체를 생각하면 쉽다)내부적으로 복사 의미가 애매하거나 위험한 객체이런 객체를 실수로 복사하면 다음과 같은 ..
이 항목의 핵심은 간단하다.클래스의 생성/복사/대입/소멸 동작을 내가 명시하지 않으면 컴파일러가 "합리적이라고 판단한 기본 동작"을 넣어 준다.문제는 이 기본 동작이 "컴파일은 되지만 의도는 틀린 코드"를 만들 수 있다는 점이다. 특히 리소스 소유권(메모리, 파일, 소켓, 뮤텍스)을 다루는 클래스에서 위험하다.1. 컴파일러가 자동으로 만들 수 있는 함수C++ 클래스에서 특별히 선언하지 않으면 컴파일러가 다음 멤버 함수를 자동으로 선언할 수 있다.기본 생성자(default constructor)소멸자(destructor)복사 생성자(copy constructor)복사 대입 연산자(copy assignment operator)C++11 이후에는 이동 의미(move semantics)가 추가되어 아래도 상황에..
1. 왜 초기화가 중요한가초기화되지 않은 객체를 쓰면 버그가 바로 드러날 때도 있고, 꽤 잘 재현되는 것처럼 보일 때도 있다.문제는 그 재현성이 신뢰할 만하지 않다는 점이다. 빌드 옵션이나 코드 배치, 실행 환경이 바뀌면 증상이 달라지거나 갑자기 사라질 수 있다.핵심은 단순하다.초기화되지 않은 값은 믿을 수 없다.컴파일러가 항상 자동으로 올바른 초기화를 해주지 않는다.특히 기본 타입(int, double, 포인터 등)은 상황에 따라 초기화가 되기도 하고 안 되기도 한다.int x; // 초기화되지 않음 (값 미정)double y; // 초기화되지 않음 (값 미정)int* p; // 초기화되지 않음 (쓰레기 주소 가능)이 상태에서 값을 읽으면 동작이 예측 불가능해진..
System Call목차시스템 콜 정의시스템 콜 제공시스템 콜 세부구성시스템 콜 구현시스템 콜 정의시스템 콜(System Call)은 사용자 공간(User Space) 과 커널 공간(Kernel Space) 사이를 이어주는 인터페이스다.시스템 콜이 필요한 이유는 크게 3가지다.하드웨어를 직접 다루지 않아도 되게 해준다.예) 파일 입출력을 할 때, 애플리케이션은 디스크 구조나 파일시스템 내부 구현을 몰라도 된다.보안과 안정성을 지켜준다.예) 커널이 중간에서 권한 검사와 자원 접근 통제를 수행한다.프로세스마다 가상화된 실행 환경을 제공한다.예) 각 프로세스는 자신만의 주소 공간을 가진 것처럼 동작한다.리눅스에서 사용자 공간 프로세스가 커널 기능을 사용하려면, 기본적으로 시스템 콜 경로를 거쳐야 한다.트랩(T..
1. 왜 const를 사용해야 하는가const를 쓰는 이유는 간단하다. "바뀌면 안 되는 값을 못 바꾸게 만들기" 위해서다.의도의 전달const를 붙이면 "이 값은 안 바뀐다"는 약속을 코드에 직접 적는 셈이다. 그래서 나중에 코드를 읽는 사람(미래의 나 포함)도 의도를 바로 이해할 수 있다.컴파일러를 통한 실수 방지const 값은 바꾸려고 하면 컴파일 단계에서 바로 에러가 난다. 프로그램을 실행하기 전에 실수를 잡을 수 있다는 뜻이다.const int maxSize = 100;maxSize = 200; // 컴파일 에러 → 실수를 즉시 발견핵심은 "내가 조심하자"가 아니라 "컴파일러가 막아주게 하자"다. const를 붙일 수 있으면 가능한 붙이는 편이 안전하다.2. const의 적용 범위const는 생..
