[완료]Byte 경계를 넘는(?) 비트필드 값의 해석..

Hamyt88의 이미지

이걸 뭐라고 설명해야 할지 잘 모르겠네요.

요즘 C를 사용해서 네트워크로 데이터를 수신하는 프로그램을 만들고 있는데 72bit의 데이터 블록으로 수신합니다. Big Endian이더군요.
일단은

struct data_block{
    unsigned char[9] __body;
};

라고 구조체 선언해서 수신까지 해 놓긴 했는데 이 안에 든 데이터를 해석해야 합니다.

데이터를 해석을 하다 보니 바이트 경계를 넘어서 이어서 해석해야 하는 경우가 필요해졌습니다.

이런식으로 두 바이트가 있다고 한다면

 12345678 12345678 .....
+--------+--------+----
|   1st  |  2nd   |
+--------+--------+----

1st bit의 1~4번째 bit까지 하나의 값, 1st bit 5 ~ 2nd bit 4까지 하나의 값, 2nd bit 5~8까지 하나의 값... 이런 식으로 byte의 경계를 넘어 값이 이어집니다...

little endian 클라이언트에서 이걸 깔끔한 코드로 읽어낼 방법이 없을까요?
지금은 매크로 몇개 만든것 + 바이트 단위로 순서 바꾸고 비트연산해서 밀어내고 하다보니 점점 코드가 알아보기 힘들어지네요...

* 업무용 코드라 올리지 못하는것 양해 바랍니다.

라스코니의 이미지

쓰시면 됩니다.

위와 같은 경우라면

struct data_block {
    unsigned char[9] __body;
};<\code>
 
밑에
 
union _test {
    struct _bf {
        unsigned VAL1 : 4;
        unsigned VAL2 : 8;
        unsigned VAL3 : 11;
        ...
    } bf;
    struct data_block _tstblock;
}
 
사용은 
 
struct data_block tst_blk;
union _test       tst;
 
tst._tstblock = tst_blk;
 
unsigned int value = tst.bf.VAL1;

unipro의 이미지

질문은 "바이트 순서가 다른 이기종간에 바이트를 넘나드는 비트필드를 깔끔하게 처리하는 방법"인데,
답변자께서 질문을 "비트필드를 깔끔하게 처리하는 방법"으로만 해석하신 듯 합니다.
저도 예전에 이런 문제를 깔끔하게 처리하는 방법에 대해 고민했는데, 뾰족한 방법이 없더라구요.

바이트가 구분되는 비트필드면, 아래의 RTP 구조체 처럼 정의하면 되는데,
아닌 경우는 어떻게 해야 할까요?

typedef struct {
	/* The following are pointers to the data in the packet as    */
	/* it came off the wire. The packet it read in such that the  */
	/* header maps onto the latter part of this struct, and the   */
	/* fields in this first part of the struct point into it. The */
	/* entire packet can be freed by freeing this struct, without */
	/* having to free the csrc, data and extn blocks separately.  */
	/* WARNING: Don't change the size of the first portion of the */
	/* struct without changing RTP_PACKET_HEADER_SIZE to match.   */
	uint32_t	*csrc;
	char		*data;
	int		 data_len;
	unsigned char	*extn;
	uint16_t	 extn_len;	/* Size of the extension in 32 bit words minus one */
	uint16_t	 extn_type;	/* Extension type field in the RTP packet header   */
	/* The following map directly onto the RTP packet header...   */
#ifdef WORDS_BIGENDIAN
	unsigned short   v:2;		/* packet type                */
	unsigned short   p:1;		/* padding flag               */
	unsigned short   x:1;		/* header extension flag      */
	unsigned short   cc:4;		/* CSRC count                 */
	unsigned short   m:1;		/* marker bit                 */
	unsigned short   pt:7;		/* payload type               */
#else
	unsigned short   cc:4;		/* CSRC count                 */
	unsigned short   x:1;		/* header extension flag      */
	unsigned short   p:1;		/* padding flag               */
	unsigned short   v:2;		/* packet type                */
	unsigned short   pt:7;		/* payload type               */
	unsigned short   m:1;		/* marker bit                 */
#endif
	uint16_t          seq;		/* sequence number            */
	uint32_t          ts;		/* timestamp                  */
	uint32_t          ssrc;		/* synchronization source     */
	/* The csrc list, header extension and data follow, but can't */
	/* be represented in the struct.                              */
} rtp_packet;

내 블로그: http://unipro.tistory.com

cococo의 이미지

Big Endian <-> Littne Endian 이라면, 지금 하시는 방법 이외에 별다른 방법이 없지 않을까요?

Hamyt88의 이미지

새로 만들면서 구조체와 공용체를 열심히 뒤섞어서(...) C코드에서 깔끔하게 `읽기'는 성공했는데 C++에서 불러다 쓰려니 또 문제가 생겨버렸습니다.

결국은 메시지 하나하나 다 읽기 함수를 만들어야겠군요.
메시지구분값은 위치가 정해져있으니.

라스코니의 이미지

C++에서 불러다 써도 잘 되야 하는데요.
어떤 문제인지요?

planetarium의 이미지

언어보다도, read는 성공했는데 write에 문제가 있다는 말씀 같네요.
근데 padding 끄고 bitfield 구조체 사용하면 안되는건가요?

unipro의 이미지

깔끔하게 `읽기'는 성공하셨다니 어떤 식으로 처리했는지 궁금하네요.

내 블로그: http://unipro.tistory.com

Hamyt88의 이미지

구조체 내부에 공용체 중첩해서 선언하고 등등의 뻘짓을 통해
실제 읽기는 버퍼에서 memcpy로 가능하게 만들었습니다.

문제는 구조체가 복잡해져서 읽기가 간단해진것 따위로는 위안이 되지 않는다는거지요...

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.