C++ 구조체 vs 클래스: 임베디드 개발자를 위한 실용 가이드
C++은 임베디드 시스템에서 여전히 틈새 선택지이지만, 프로젝트가 순수 C의 한계를 넘어설 때 가장 선호되는 언어가 됩니다. C에서 전환하는 개발자에게 C 구조체, C++ 클래스, C++ 구조체 간의 미묘한 차이를 이해하는 것은 필수적입니다. 이 기사는 명확한 예제와 모범 사례 조언으로 이러한 언어 요소를 명확히 설명합니다.
C의 구조체
C에서 struct는 관련 값들을 집계하는 복합 데이터 타입입니다. 내장 타입(예: int, char), 비트 필드, 또는 다른 구조체를 포함할 수 있습니다. 그 목적은 논리적으로 관련된 데이터를 단일 객체로 그룹화하는 것입니다.
struct coordinates { float x; float y; float z; };
컴파일러는 struct coordinates의 레이아웃을 학습하여 다음과 같이 변수를 선언할 수 있게 합니다:
struct coordinates location;
그런 다음 점 연산자를 사용하여 개별 필드에 접근할 수 있습니다:
location.x = 1.0; location.y = 2.0; location.z = 9.99;
세 개의 별도 float 변수를 사용할 수도 있지만, 이를 단일 구조체로 그룹화하면 함수로 데이터 전달이 간단해지고 가독성이 향상됩니다.
비트 필드는 구조체에 독특한 능력을 부여합니다: 멤버의 정확한 비트 폭을 지정할 수 있게 하여 하드웨어 레지스터 모델링에 유용합니다.
struct bitreg { unsigned up: 3; unsigned down: 3; unsigned polarity: 2; };
struct bitreg 타입의 변수는 일반적으로 1바이트를 차지하며, 컴파일러는 필요한 마스킹과 시프팅 코드를 자동으로 생성합니다. 사용법은 간단합니다:
struct bitreg control; control.up = 1; control.down = 2; control.polarity = 3;
임베디드 하드웨어 작업 시 두 가지 주의사항이 있습니다:
- 최신 32비트 CPU는 구조체 조작을 효율적으로 지원하지만, 저가형 프로세서는 그렇지 않을 수 있습니다. 성능 페널티를 피하기 위해 구조체를 신중하게 사용하세요.
- 비트 필드 레이아웃은 구현 정의입니다. 컴파일러 변경이나 업데이트로 필드 순서나 정렬이 변경되어 하드웨어 레지스터 접근이 깨질 수 있습니다. 또한 컴파일러가 여러 읽기/쓰기 연산을 생성할 수 있어 쓰기 전용 레지스터에 문제가 될 수 있습니다.
C에서 구조체는 본질적으로 수동적 컨테이너이며, 필드 접근 외에는 동작을 호출할 수 없습니다. 이 한계는 C++에서 해결됩니다.
C++의 클래스
C++은 class 구조를 도입하여 구조체 아이디어를 데이터와 동작을 모두 캡슐화할 수 있는 완전한 데이터 타입으로 확장합니다. 클래스의 인스턴스는 객체입니다.
클래스는 C 구조체와 문법을 공유하지만 몇 가지 강력한 기능을 제공합니다:
- 멤버 함수(메서드)를 포함할 수 있습니다.
- 멤버는 기본적으로 private으로 캡슐화를 제공합니다. public:이 앞에 와야 public이 됩니다.
- 객체 생성과 소멸 시 자동으로 실행되는 특별한 생성자와 소멸자가 있습니다.
- 연산자 오버로딩으로 내장 연산자의 사용자 정의 동작을 정의할 수 있습니다.
- 상속으로 한 클래스가 다른 클래스에서 파생되어 코드 재사용을 촉진합니다.
- 객체 선언 시 클래스 이름만 사용하면 됩니다. class 키워드는 필요 없습니다.
예제:
class myclass { char a; int b; public: void fun(); myclass(); ~myclass(); }; myclass myobj; myobj.fun();
데이터 멤버 a와 b는 클래스의 멤버 함수 내에서만 접근 가능합니다. 생성자와 소멸자는 객체 수명 주기를 관리합니다. 함수 본문은 범위 결정 연산자를 사용하여 다른 곳에서 정의됩니다:
void myclass::fun() { // 구현 }
C++의 구조체
C++도 struct를 지원하며, 이는 C와 완전히 호환되면서 클래스의 추가 기능을 상속받습니다. 유일한 차이점은 멤버가 기본적으로 public이라는 점이고, 클래스 멤버는 기본적으로 private입니다.
앞선 클래스 예제와 동등한 구조체는 다음과 같이 작성할 수 있습니다:
struct mystruct { void fun(); myclass(); ~myclass(); private: char a; int b; };
클래스와 구조체 선택하기
규율 있는 접근 방식을 채택하세요: 수동적 데이터 컨테이너만 필요할 때, C 스타일을 반영하여 struct를 사용하세요. 캡슐화, 동작, 또는 상속이 필요할 때는 class를 사용하세요. 이 관례는 코드 가독성과 유지보수성을 개선합니다. 이는 장기 임베디드 프로젝트의 핵심 자질입니다.
명확하고 자기 문서화되는 코드가 영리한 트릭보다 더 가치 있음을 기억하세요. 미래의 유지보수자들(심지어 인내심이 짧은 사람들도)은 일관된 스타일에 감사할 것입니다.