비트필드를 오버플로우에 대한 문제

kinys4의 이미지

매 프레임 들어오는 8바이트 메세지를 받아서 정렬을 해야합니다.
받아서 8바이트 배열을 구조체로 넘겼습니다.

<code>
typedef union { // size = 8 byte
 
  uint8_t bytes[8];
  struct {
	uint8_t a: 4;
	uint8_t b: 2;
	uint8_t c: 2;
	uint16_t d: 12;
	uint16_t e: 16;
	} Test
}

31 6d ff f7 2f 0f e2 41 이렇게 들어왔다고 예를들면,

a, b, c는 1바이트, 0x31에 대한 비트를 나눠 가져서

a =0x01
b=0x03
c=0x00

이런식으로 옳게 받을 수 있었습니다.

하지만 d(12비트짜리)를 2바이트로 선언후 잘 받았고,
d= 0x0f6d

바로 뒤이어서 e값을 받고 싶었습니다. 옳게 받았다면
e = 0xff7f 가 나와야 하지만 오버플로우가 발생하여 12비트를 사용하였음에도 16비트를 건너뛰고

새로 시작하여
e = 0x2ff7이 나옵니다.

데이터 형을 uint32_t로 하면 문제는 해결되지만 32가 오버플로우 났을경우에도 같은 문제가 발생합니다.

https://docs.microsoft.com/ko-kr/cpp/cpp/cpp-bit-fields?view=vs-2019
위 사이트에서 설명을 보았는데 잘 되지 않아서 여기에 글을 남깁니다. 하루종일 ㅜㅜ 씨름했더니 머리가 너무 아픈데 고수님들 부탁드리겠습니다..

File attachments: 
첨부파일 크기
Image icon 1.PNG38.94 KB
라스코니의 이미지

우선 Test 내부의 bit 개수가 8X8, 64가 안되는 것은 제외하더라도,
union을 안쓰고 하는 것을 고려해 보세요.

저는 이전에 union의 열렬한 팬이었지만 union 내부의 bit field structure는 엔디안의 영향을 크게 받고 또 특정 CPU에서는 심할 정도로 성능이 떨어집니다.

꼭 union을 쓸 필요가 없으면 아래처럼 해보세요.

a = (bytes[0] & 0xf0) >> 4;
b = (bytes[0] & 0xc0) >> 2;
c = (bytes[0] & 0x03);
...

등으로요.
Stephen Kyoungwon Kim@Google의 이미지

bitfield가 포함된 struct의 layout 일반은 같은 플랫폼 내에서도 deterministic하지 않죠. endian도 문제고 packing을 어떻게 할지도 문제고 implementation에서 컨테이너(?) 사이즈도 문제입니다.

* 같은 플랫폼 내에서는 deterministic 해야할 것 같네요. 오랜 기억이라서 다른 거랑 헷갈린 것 같습니다. 그런데 플랫폼 별로는 언어가 레이아웃을 deterministic하게 스탠다드에서 정하지 않기 때문에 다를 수 있으리라 생각합니다.

kinys4의 이미지

사실 비트단위 연산으로 하는 코드를 짜놓긴 하고 그것이 정답지라고 생각하고 union을 이용하는 방법을 코딩하고 있었습니다. 생각대로 잘 되지 않아서 질문했는데 bit field structure의 단점에 대해서도 알게 되었네요 감사합니다^^!

Stephen Kyoungwon Kim@Google의 이미지

왜냐면, 저수준에서는 워드 바이너리를 넘어서 어중간하게 걸친 데이터를 가져오려면 복수의 연산이 필요하기 때문에 보통 비트 필드도 (이걸 지칭하는 표준 용어가 없습니다만) 컨테이너에 넣고 align을 시키기 때문입니다.

컨터이너가 32비트 사이즈인 경우 (이 경우), e까지 한 컨테이너에 못 들어가죠. 그래서 e는 새 컨테이너에 넣게 됩니다. 비트 필드 말고 다른 작은 사이즈의 필드까지 뒤섞여 있게 되면 더 복잡해집니다.

게다가 표준이 단 하나의 레이아웃을 디터미니스틱하게 정하지 않습니다. 그래서 같은 플랫폼에서도 컴파일러에 따라 다르게 할 여지가 있습니다. data analysis 상의 차이 같은 것 때문에 다르게 하기도 합니다.

포인터도 없는데 json이나 xml 같은 텍스트 포맷처럼 뭔가 포터블한 포맷으로 보내고 받아서 그때그때 인-메모리 데이터를 구축하는 게 맞는 방향 아닌가 싶습니다.

*컴파일러에 따라 다르다는 건 제 기억이 잘못 된 것일 수 있겠네요. 잘 생각해 보니 그렇게 하면 바이너리 컴패터블 하지 않을 거 같은데, 플랫폼별로는 같을 듯 합니다.

댓글 달기

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