C++ for Pixhawk

C++ 발표 자료(추가)

https://docs.google.com/presentation/d/1utKTH0baDk7a2X9YDm-M3QjpMTWS9nqMAcuXNr4Tejc/edit


목적

  • Pixhawk 소스코드 읽기
  • 기존 C개발자가 쉽게 C++ 코드 읽을 수 있게
  • Pixhawk에서 자주 사용한 C++ 패턴
  • OpenSource 개발자 되기 (http://subak.io/?p=892)
  • Embedded에 자주 사용하는 C++

대상

  • Pixhawk 관련 개발자
    • C/Java 개발자
  • Embedded 개발자
  • RTOS 개발자

C vs. C++

  • C++의 부분집합
  • C++ 너무 복잡해요!
  • Pixhawk에 사용된 C++에 집중하고 넓혀 나가기

build

  • main.cpp 파일 생성
  • Build
> g++ main.cpp -std=c++11
  • Run
 > ./a.out

namespace

  • 소스 관리 목적
  • 모듈화
  • 방법
    • 디렉토리 기반
    • namespace 기반

namespace

namespace myspace{
  void f() {
    cout<<"myspace::f();"
  }
}

namespace yourspace{
  void f() {
    cout<<"yourspace::f();"
  }
}

namespace

int main()
{
    myspace::f();
    yourspace::f();
}

namespace

  • 찾아보기
    • Firmware/src/drivers/device/cdev.cpp
  • 실제 사용 예제 찾기

const

  • 목적은?

const

class foobar
{
private:
  int counter;

public:
  void Foo() const
  {
    cout<<counter++;
  }
}

const

  • const의 사전적 의미
  • 일반적인 사용 예제
  • read-access function

const

  • class의 method 끝에 사용
  • void Foo() const 내부에서 member 변수를 변경할 수 없다.
  • 접근은 가능
    class A
    {
    public:
    void Foo() const { ... }
    };
    

const

  • 찾아보기
    • Firmware/src/drivers/batt_smbus/batt_smbus.cpp
  • 실제 사용 예제 찾기

class

  • C와 구별되는 C++의 핵심 기능, 객체지향프로그래밍
  • class를 구성하는 것들에 대한 정의 이해
class A
{
public: //접근 제한자
  int a; //member data
  void foo(); //멤버함수, method
private:
  int a1;
  void bar();
};

class

  • x, y 좌표를 가지는 Point 클래스
class Point
{
priate :
  int x, y;
public:
  Point(int, int);
  int getArea();
};

class

  • 찾아보기
    • Firmware/src/drivers/airspeed/airspeed.cpp
  • 실제 사용 예제 찾기

Friend

  • 상속 관계가 아님
  • 다른 class의 private나 protected memeber에 접근 가능
class Rectangle {
  int width, height;
public:
  int area() { return width*height; }
  void convert(Square a);
};

void Rectangle::convert(Square a)
{
  width = a.side; //친구라고 인정해 줬으니 Square의 private 멤버에 접근 가능
  height = a.side;
}

class Square {
  friend class Rectangle; //Rectangle은 내 친구야~
private:
  int side;
public:
  Square(int a): side(a) {}
};

Friend

  • 찾아보기
    • Firmware/src/drivers/mpu6000/mpu6000.cpp
  • 실제 사용 예제 찾기

상속

  • public, protected, private
class A
{
private:
  int a;
protected:
  int b;
private:
  int c;
};

class B: public A
{
};

class B: protected A
{
};

class B: private A
{
};
 | Base클래스\상속형태 | public | protected  |  private  |
 | ------------- |:-------------:| -----:| -----:|
 | public 멤버     | public(외부O) | protected | private  |
 | protected 멤버 | protected |  protected |  private |
 | private 멤버 | X  | X | X  |

상속

  • 찾아보기
    • Firmware/src/drivers/airspeed/airspeed.h
  • 실제 사용 예제 찾기

Template

  • Generic Programming
    • 프로그래밍 스타일 중에 하나
    • 알고리즘에서 type을 최대한 뒤에 지정하는 방식으로 필요한 시점이 되면 type을 parameter로 지정한다.
    • type만 다른 경우 코드 중복을 제거
    • 파라미터가 많이 사용되면 코드 읽고 이해하기 어려워진다는 단점

Template 예제

template <typename T>
class Stack
{
private:
  vector<T> elems;

public:
  void push(T const&);
  void pop();
  T top() const;
  bool empty() const {
    return elems.empty();
  }
};

void main()
{
  Stack<int> intStack;
  Stack<string> stringStack;
  //....
}

Template

  • 찾아보기
    • Firmware/src/platforms/px4_message.h
    • Firmware/src/modules/uavcan/libuavcan/libuavcan/include/uavcan/node/generic_publisher.hpp
  • 실제 사용 예제 찾기

virtual

  • 순서 가상함수에서는 A에서 선언하고 이를 상속한 B에서는 반드시 구현부가 있어야 한다.
  • 상속 관계에서 method overriding시에 어떤 멤버 method가 호출되는지 이해

virtual 예제

class A
{
public:
    virtual int f()=0;
};

class B: public A
{
public:
  int f() { return 2; }
};

class C: public A
{
public:
  int f() { return 3; }
};

void main()
{
  A* a = new A_kind_class;
  a->f(); //B or C를 결정하고 적절한 f()를 호출
}

virtual

class Animal
{
    pubic:
    void eat() { std::cout << "I'm eating generic food.";}
}

class Cat : public Animal
{
    public:
    void eat() { std::cout << "I'm eating a rat."; }
}

Animal* animal = new Animal;
Cat* cat = new Cat;

animal->eat();
cat->eat();


void func(Animal* xyz) { xyz->eat(); }

func(animal); //"I'm eating generic food."
func(cat);    //"I'm eating generic food."

virtual

  • 찾아보기
    • Firmware/src/drivers/bmp280/bmp280.h
    • Firmware/src/drivers/airspeed/airspeed.h
  • 실제 사용 예제 찾기

operator overloading

  • 함수 호출 대신 연산자만을 이용해서 함수의 동작을 할 수 있도록 하는 문법
  • 사용 가능한 operator
    • 할당 연산자 : =
    • 수치 연산자 : +, -, *
    • 복합할당 연산자 : +=, -=, *=
    • 비교 연산자 : ==, !=

operator overloading 예시

class A
{
private:
  int x, y;
public:
  A operator+(const A& a1, const A& a2);
};
A operator+(const A& a1, const A& a2)
{
  A a(a1.x+a2.x, a1.y+a2.y);
  return a;
}

void main()
{
  A a1(1, 2);
  A a2(3, 4);
  A a3 = a1 + a2;
  //...
}

nullptr

  • C++11에서 추가
  • NULL vs. nullptr
    • #define NULL 0 vs. std::nullptr_t
  • pointer literal
  • nullptr에서 다양한 포인터 타입의 null pointer value로 implicit conversion 가능.
  • '진짜 null pointer야!'

nullptr 예시

void f(int *p);
void f(int v);

f(nullptr); // f(int *p) 호출
f(0);       // f(int v) 호출
f(NULL);    // f(int v) 호출
#include <cstddef>
#include <iostream>

template<class F, class A>
void Fwd(F f, A a)
{
    f(a);
}

void g(int* i)
{
    std::cout << "Function g called\n";
}

int main()
{
    g(NULL);           // Fine
    g(0);              // Fine

    Fwd(g, nullptr);   // Fine
//  Fwd(g, NULL);  // ERROR: No function g(int)
}

nullptr

  • 찾아보기
    • Firmware/src/drivers/airspeed/airspeed.cpp
  • 실제 사용 예제 찾기

const_cast

  • 함수에서 const가 아닌 인자가 들어가는 자리에 const pointer를 사용할 수 있다.
  • const가 아닌 인자를 받는 파라미터에 const 타입을 사용할 수 있다.
  • pointer가 가리키는 obj의 const 속성을 보호하기 위해서

const_cast 예제

void print(char *str)
{
    //str[0] = 'a'; compile마다 다른 처리. -> 문제상황
    cout<<str<<"\n";
}

int main()
{
    const char *c = "test";
    //print(c); //compile error발생
    print(const_cast<char *>(c));
    return 0;
}

static_cast

  • 관련 class들(상속관계)에 대한 pointer에 대해서 변환 (up/downcast 가능)
  • obj가 변환을 보장을 위한 check를 compile time(O), runtime(X) -> 모든게 개발자 책임!
  • dynamic_cast의 type안전성 체크의 overhead가 없다. -> embedded에 사용.
  • static_cast ( expression )
  • http://en.cppreference.com/w/cpp/language/static_cast

class Base {};
class Derived: public Base{};
Base *a = new Base;
Derived *b = static_cast<Derived*>(a);

static_cast

  • 찾아보기
    • Firmware/src/drivers/rgbled/rgbled.cpp
    • Firmware/src/drivers/sf0x/sf0x.cpp
  • 실제 사용 예제 찾기

reinterpret_cast

  • pointer type을 다른 pointer type으로 변환.(관계 없는 class끼리도 가능)
  • 연산 결과는 pointer에서 다른 pointer로 binary 값의 복사가 일어난다.
  • 따라서 모든 pointer 변환이 가능하다. 가리키는 내용과 pointer type에 대한 검사를 수행하지 않는다. -> 가장 위험 개발자가 모든 책임을 진다.
  • 컴파일러마다 다르므로 주의

class A {};
class B {};
A* a = new A;
B* b = reinterpret_cast<B*>(a);

reinterpret_cast

  • 찾아보기
    • Firmware/src/drivers/camera_trigger/camera_trigger.cpp
  • 실제 사용 예제 찾기