Type이라는 클래스에 unsigned int 캐스팅 연산자를 정의하는 방법이 맞을까요?

dltkddyd의 이미지

Type이라는 형을 cpu의 byte order(little endian, big endian)에 따라 unsigned int로 캐스팅하는 연산자를 다르게 처리하도록 했는데 맞게 정의했는지 확신이 안 섭니다. 제가 big endian 식으로 처리하는 컴퓨터를 갖고 있지 않으니 알고리즘을 작성했어도 확인할 방법도 없고요. 다음과 같이 캐스팅 연산자를 구현해봤습니다.

class Type {
private:
  unsigned int a:8;
  unsigned int b:8;
  unsigned int c:8;
  unsigned int d:8;
public:
  operator unsigned int() {//편의상 인라인으로 구현한 점 양해부탁드립니다.
  	unsigned int tmp;
	if(is_little_endian()) {//little endian 방식으로 처리하는 cpu 종류는 여기서 캐스팅
		tmp=d;
 
		tmp<<=8;
		tmp |=c;
 
		tmp<<=8;
		tmp |=b;
 
		tmp<<=8;
		tmp |=a;
 
		return tmp;
	}
	else {//big endian 방식으로 처리하는 cpu 종류는 여기서 캐스팅
		tmp=a;
 
		tmp<<=8;
		tmp |=b;
 
		tmp<<=8;
		tmp |=c;
 
		tmp<<=8;
		tmp |=d;
 
		return tmp;	
	}
  }
}

is_little_endian() 함수는 cpu가 little-endian 방식일 경우에는 true를 반환합니다. 그렇지 않을 경우에는 big-endian을 반환하도록 만든 함수입니다. 제가 보기에 shift 연산자를 little endian의 경우는 물리적인 공간에서 반대방향으로 처리를 하는 것 같습니다. 리틀 엔디언 방식의 제 컴퓨터로 확인해보니 역방향으로 움직이는 것을 확인할 수 있었습니다. 그런데 빅 엔디언은 잘 모르겠네요. 제 짐작(어디까지나 짐작)에는 물리적 공간에서 순방향으로 움직이지 않을까라고 예상하는데요. 저 빅 엔디언의 경우 처리하는 알고리즘이 정확하게 값을 캐스팅 한다면 빅 엔디언은 쉬프트 연산을 순방향으로 처리한다는 예상이 맞을텐데요. 이것좀 확인해주실수 없을까요?

peecky의 이미지

쉬프트 연산이랑 엔디안은 무관합니다. 리틀 엔디안이든 빅 엔디안이든 value << n 하면 2^n 배가 됩니다.

C에서 포인터나 union을 사용하는 경우 외에는 대부분 엔디안이랑 무관합니다.

dltkddyd의 이미지

struct st{
unsigned int a:8;
unsigned int b:8;
unsigned int c:8;
unsigned int d:8;
}

에서 a, b, c, d가 메모리에서 배열되는 순서(주소앞과 뒤를 차지하는 순서 말입니다.)는 어떻게 되는지요?

cpu가 리틀방식이든 엔디언 방식이든, a, b, c, d의 순서 아닌가요.

0x0001이라는 값이 들어가는 순서는 어떻게 되는지요?

리틀 엔디언도

0xeeefab01      0xeeefab02      0xeeefab03    0xeeefab04
          a         b               c             d

빅 엔디언도

0xeeefab01    0xeeefab02      0xeeefab03      0xeeefab04
         a        b                c              d

이런 식으로 배열되는 것 같은데요. 다만 값이 들어가는 방향이 다르다는 게 리틀과 빅 엔디언의 차이인 것 같습니다. 리틀 엔디언이란 저 비트구조체의 나열 순서를 바꾸는 것으로 알았는데, 그게 아니던데요. a, b, c, d는 순서대로 나열됩니다. 빅 엔디언인 컴퓨터에서 operator unsigned int() 캐스팅 연산자 알고리즘이 제대로 작동되는지 확인좀 부탁드립니다. 아마 맥 컴퓨터가 빅 엔디언 처리방식으로 cpu가 작동되는 것으로 압니다. 맥 컴퓨터 갖고 계신 분 안 계신가요?
그러니까 인텔 처리 방식으로는

unsigned int tmp=0x000000ff;
st sval=tmp;//1)

라고 할 때
1)에 대한 처리는 다음과 같아야 합니다.
그 전에 먼저 tmp가 차지하는 메모리에 0x000000ff라는 값은 다음과 같이 들어갔겠죠.

ff 00 00 00

이 점을 상기하면서

sval.a=0xff;

라고 한 다음에는 b에 값을 할당하기 위해
tmp> >=8;//처음에는 tmp의 메모리 구조를 보고 tmp<<=8이 되어야 한다고 생각했습니다. 그런데 아니던데요.

tmp> >=8;

이라고 해야 tmp가 제대로 shift가 됩니다. 오른쪽으로 shif 할 때 메모리에서는 왼쪽으로 값이 이동합니다. 그래서 역방향으로 움직인다고 생각하는데요. 메모리 구조를 감안하지 않고 논리적인 값

0x 00 00 00 ff

을 생각한다면 순방향이지만 그건 순전히 논리적인 이동방향일 뿐이죠. 머신에는 ff000000으로 값이 나열되어 있으므로 오른쪽 쉬프트는 왼쪽으로 값이 빠져나가도록 명령을 내리는 것이라고 보는데요. 인텔과 같은 처리방식(리틀 엔디언)에서는 이게 확실한 것 같습니다. 조언주신 대로 쉬프트와 관계없다고 말씀하신 것은 논리적인 구조를 생각하면서 말씀하신 것으로 생각됩니다. 물리적인 방향에서 검토해보신다면 다르지 않나요? 그리고 서글프게도 빅엔디언 방식에 대해서는 점검해볼 환경이 안되네요. 이에 대해 설명해주실 분 안 계신가요?

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

peecky의 이미지

a, b, c, d의 주소값 순서는, 컴파일러를 구현하기 나름이라 생각합니다만, 제 경험상으론 tunecolor님에 말씀하신 순서랑 부합합니다.

지금 맥을 쓰고 있지만 요즘 맥은 전부 인텔 CPU를 쓰는 관계로 리틀 엔디안입니다.
대학교 다닐 때는 전산실의 솔라리스 머신이 빅 엔디안이어서 이것 저것 테스트해봤는데, 졸업한 후로 빅 엔디안 머신을 직접 접할 기회가 없네요.

shift연산자를 사용할 때 '구동중인 머신'의 엔디안을 고려할 필요는 없습니다. 컴파일할 때 해당 머신에 맞춰서 변환된다고 생각해도 됩니다.

엔디안에 대해 생각할 때 바이트 단위로 생각하면 헷갈리기 쉽습니다. 비트 단위로 생각해보세요.

    unsigned int tmp = 0xAA; // AA(hex) == 10101010(bin)
    unsigned int i = tmp < < 3;

라고 했을 때 i 값은 리틀 엔디안일 때와 빅 엔디안일 때 각각 얼마가 될까요?
익명 사용자의 이미지

The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined.

따라서 사용하고 있는 컴파일러 메뉴얼을 확인하는 것이 가장 정확합니다.
대체로 ABI의 룰을 그대로 따르는 경향이 있습니다만, 어쨌거나 implementation-defined 입니다.

비트 필드와 관련하여 많은 부분이 implemetation-defined이기 때문에(예를 들어 메모리 정렬 혹은 메모리 저장 단위에 의한 padding 존재 여부라던가), 이식성 있는 동작 또는 일반적인 동작은 기대하지 않는 것이 좋습니다.

특정 데이터 타입의 내부 표현을 보고 싶으면 unsigned char형 포인터로 접근해서 보는게 가장 낫습니다.

dltkddyd의 이미지

shit 연산은 논리적인 구조를 생각하며 어디로 이동할지를 결정하는 것이군요. 비트구조는 컴파일 나름이니, 논리적인 이동방향을 생각하며 물리적인 이동방향을 생각하면 그 실제로 이동되는 방향을 알 수 있겠군요. 그리고 반문하신 저 연산의 결과는 (처음 입력값*2의 삼제곱)이겠네요. 답변 감사드립니다.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

endianess는 load/store와 관계있지 shift와는 무관합니다. 말을 이렇게 하든 저렇게 하든 변하지 않습니다.

big endian 알고리즘이 맞는지 확인하는 방법

(실행하는 컴퓨터의 endianess와는 무관하게) big endian 머신에서 값이 저장되는 방식대로 값을 메모리에 저장한 뒤 돌려본다.

댓글 달기

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