protocol을 코딩으로 나타내기위한 효율적인 방법

삼구의신의 이미지

통신 프로토콜이 있습니다.

예를들어 아래처럼 로봇을 움직이는 명령이 있다고 할때

01 00 : 왼손 왼쪽으로 1 움직이기
01 11 : 왼손 오른쪽으로 1 움직이기
02 00 : 오른손 오른쪽으로 1 움직이기
02 01 : 오른속 오른쪽으로 1 움직이기

등과 같이 2 BYTE로 이루어진 명령어가 있을 때
장치로부터 넘어온 명령어 data를 저장하려고 합니다.

함수를 사용하는 목적은, 각 명령어마다 Data값을 저장하는 구조체가 있습니다.
명령어가 들어오면, 그 명령어에 해당하는 변수에 들어온 데이터를 저장하려는 기능입니다.

ex)
struct cmdData // 데이터 저장 구조체
{
unsigned char rightHand[MAX_SIZE];
unsigned char rightleg[MAX_SIZE];
unsigned char leftHand[MAX_SIZE];
unsigned char leftleg[MAX_SIZE];
}

switch(cmd) // 명령어가 들어왔을때 switch문
{
case LEFT_HAND: // left hand 에 관한 데이터가 들어왔을 때 left hand 변수에 값 저장
saveData(cmdData.leftHand,newData);
break;
}

이런식으로 새로 들어온 데이터틀 변수에 저장하려고 하고있습니다.

현재 switch 문으로 앞에 1Byte를 탐색하고 뒤에 1Byte를 탐색하는 방식으로 구현했는데
너무 소스가 길어지고 있습니다.
명령어가 최소 100 ~ 500 개 정되 되는 명령어들을 효율적으로 코딩하기 위해 어떤 방법이 좋을까요??
전문가 님들의 조언을 듣고싶습니다.

ktd2004의 이미지

대략 다음과 같은 방식이면 어떨까요?

void goleft(void)
{
}
void goright(void)
{
}
struct {
 uint16_t cmd;
 void (*func)();
} CMDS[] = {
 {0x0100, goleft},
 {0x0100, goright},
}
 
for (int i=0; i<sizeof(CMDS)/sizeof(CMDS[0]); ++i) {
  if (CMDS[i].cmd == cmd) {
    CMDS[i].func();
  } 
}
삼구의신의 이미지

답변 감사합니다.

제시해주신 방법대로면 각 기능마다 함수를 구현해야하는데 200개정도의 함수를 구현하게 된다는 건데
switch문으로 한거보다 코드는 메인 함수 코드는 간결하다고 할 수 있을 것 같습니다.
좀더 나은 방법이 있는지 찾아봐야겠네요 ㅠㅠ

제가 질문부분을 너무 간소하게 쓴거 같아 세세히 수정했습니다. 다시한번 봐주시면 감사하겠습니다.ㅠㅠ

ktd2004의 이미지

말씀하신 내용이 잘 이해가 가지 않네요. ^^;
함수 포인터를 사용한 것은 하나의 예시일 뿐입니다.

"명령,동작"을 하나로 mapping하는 것이 중요한 포인트입니다.

지금 같은 경우에는 동작에 새로운 데이타를 넣는다 정도를 넣으면 되겠네요.

삼구의신의 이미지

제가 설명을 잘 못해서 죄송합니다 ㅠㅠ
답변감사합니다. 잘 참고하겠습니다.!

raymundo의 이미지

명령 코드 숫자 범위가 연속적이라면 아예 명령 코드 자체를 인덱스로 해서 호출할 수도 있겠네요.

void lefthand_left() { ... }
 
void (*CMDS[10][10])() = {
    { lefthand_left, lefthand_right, ... },    // 첫 바이트가 00인 명령들
    { righthand_left, righthand_right, ... }, // 첫 바이트가 01인 명령들
     ...
};
 
// 명령의 first_byte, second_byte 를 입력받고
CMDS[ first_byte ][ second_byte ]();

설령 명령 코드가 0부터 연속적으로 구성되지 않고 3,7,9 이런 식으로 띄어져 있더라도, 아주 메모리가 빠듯한 상황이 아니라면야 중간에 이가 빠져 있어도 상관없을 것 같고요. 아니면 배열이 아니라 해시를 쓰던가...?

좋은 하루 되세요!

삼구의신의 이미지

답변 감사합니다!.

명령어가 00 ~ 4D까지 존재하는데 중간중간 빠지는게 많아요 ㅠㅠ 그래서 다 넣기엔 어려울거 같아요..
제가 질문을 좀 이상하게 했는데, 다시 수정했습니다.

수정된것 요약하자면

명령어 2BYTE가 들어오면 그 명령어에 해당하는 구조체안에 변수에 명령어와 함께 같이 들어온 데이터를
저장하는 것이 필요합니다.

예를들어 02 01 명령어와 1 이라는 데이터가 들어왔을 때, cmdData.leftHand 라는 변수에 1을 넣어야 하는 것입니다.
단순 데이터를 변수에 넣는건데 함수를 만드는거 자체가 비효율적이란 생각이 들어서요 ㅠㅠ
다른 좋은 방법이 있을 까요???

raymundo의 이미지

2바이트의 조합 가지수가 65536가지이고 포인터가 8바이트라면 총 용량은 500KB네요. 이중 대부분이 안 쓰여서 null이라 해도 그냥 컴퓨터에서 굴리는 거면 사실 별 상관없지 싶기도 합니다만. 임베디드 시스템에서 만드신다거나 해서 그런 낭비를 피하고 싶으시면 해시를 쓰시든, 트리를 만드시든, 아니면 가장 간단하게는 윗분이 적어주신 대로 명령어-포인터의 쌍을 배열에 넣고 매번 루프 돌면서 명령어가 일치하면 그에 해당하는 포인터를 쓰는 식이 있겠지요.

그 다음, 일일이 함수를 만들 필요가 없고 모든 명령어의 동작이 다 말씀하신 방식대로라면, 함수 포인터 대신 해당 변수의 포인터를 쓰면 될 거고요.

// ktd2004 님의 코드를 바꿔서
struct {
 uint16_t cmd;
 unsigned char * destination;   // 각 cmd에 대응되는, 데이터를 저장할 변수를 가리키는 포인터
} CMDS[] = {
 {0x0100, cmdData.lefthand},
 {0x0200, cmdData.righthand},
  ...
}
 
for (int i=0; i<sizeof(CMDS)/sizeof(CMDS[0]); ++i) {
  if (CMDS[i].cmd == cmd) {   // 명령어가 일치하면
    saveData( CMDS[i].destination, newData );
  } 
}

좋은 하루 되세요!

삼구의신의 이미지

우와 이렇게 하니까 코드가 훨씬 간결해지네요. switch문을 2개나 써서 몇 천줄을 만드는게 너무 거슬렸는데
좋은 코딩 같아요 ㅎㅎㅎ
해시나 트리를 만들어 쓰는건 한번도 안해봐서 공부를 해봐야겠네요.ㅠㅠ

답변 감사합니다. 좋은 하루되세요!!

삼구의신의 이미지

한가지 궁금한게 있는데 해쉬는 공부해보니 어떻게 할지 감이오는데 트리는 어떤방식으로 이용할 수 있나요?ㅠㅠ

raymundo의 이미지

http://clojure.or.kr/wiki/doku.php?id=study:algorithms:trie

이런 것을 떠올린 겁니다만 지금 같은 경우에는 그냥 루프 도는 것보다 크게 달라질 것 같지 않긴 하네요.

좋은 하루 되세요!

삼구의신의 이미지

감사합니다.!

twinwings의 이미지


아. 질문을 다시 보니 일반적인 switch 문을 줄이는 것이 아니라 알고리즘 쪽에 가깝네요.

쓴게 아까워서 지우진 않고 남겨둡니다...

=================================================================
if문, switch문을 줄이는 가장 간단한 방법 중 하나가
- 함수 포인터
- 상속 및 함수 오버라이드

입니다. 결국 상속/함수 오버라이드도 내부적으로 함수포인터로 구현됩니다.
여기에 FactoryMethod 패턴까지 곁들이면 타입에 따른 if, switch문은 딱 한곳, FactoryMethod 내부에만 존재하게 됩니다.

예를 들어, 이렇게 표현되겠죠.

class BaseCmd;
class A_Cmd;
class B_Cmd;
 
BaseCmd* Factory(cmd_type) {
    switch(cmd_type) {
     case A: return new(A_Cmd); break;
     case B: return new(B_Cmd); break;
     default:
    }
    return NULL;
}
=======
BaseCmd *cmd = Factory(cmd_type);
cmd.do_op();

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.