2010-03-27 3 views
2

그래서 다음은 어린 아이들기본 엔디안 및 자동 변환

uint32_t ntoh32(uint32_t v) 
{ 
    return (v << 24) 
     | ((v & 0x0000ff00) << 8) 
     | ((v & 0x00ff0000) >> 8) 
     | (v >> 24); 
} 

작품에 큰 엔디안 변환합니다. 매력처럼.

나는 char v[4]에 큰 엔디안 파일에서 4 바이트를 읽고 작동하지 않는

ntoh32 (* reinterpret_cast<uint32_t *> (v)) 

로 위의 함수에 전달할 - 내 컴파일러 (VS 2005) 자동으로 빅 엔디안 문자로 변환하기 때문에 [4] 캐스팅을 할 때 little endian uint32_t에.

AFAIK이 자동 변환 휴대용되지 않습니다, 그래서

uint32_t ntoh_4b(char v[]) 
{ 
    uint32_t a = 0; 
    a |= (unsigned char)v[0]; 
    a <<= 8; 
    a |= (unsigned char)v[1]; 
    a <<= 8; 
    a |= (unsigned char)v[2]; 
    a <<= 8; 
    a |= (unsigned char)v[3]; 
    return a; 
} 

이 예 (unsigned char)이 필요 사용합니다. 예 개가 천천히.

더 좋은 방법이 있어야합니다. 누구?

+0

아니요, VC++ 컴파일러는 엔디안을 변경하지 않습니다. 다른 컴파일러도 마찬가지입니다. 귀하의 데이터 파일은 귀하가 생각하는 엔디안 방식이 아닐 수도 있습니다. 그리고 가정을 기반으로 무언가를 "개 느리게"말하는 것은 무서운 방법입니다. –

답변

2

더 나은 방법은 IMHO가 htonlntohl 기능을 사용하는 것입니다. 정말로 포터블이되고 싶다면 "리틀 엔디 언으로 변환"의 관점에서 생각할 수 없습니다. 오히려 "호스트 엔디안으로 변환"에 대해 생각해야합니다. 그게 바로 ntohl입니다. 입력이 확실히 빅 엔디 언 (네트워크 표준이 무엇인지) 인 경우입니다.

이제 바이트를 개별적으로 읽으면 부호없는 long (바이너리 모드)으로 읽을 수 있습니다. 이렇게하면 빅 엔디안을 길게 가져올 수 있으며 필요에 따라 변환 할 수 있습니다. 호스트 엔디안이 필요하면 ntohl.

+0

아마도 내 질문을 이해하지 못했습니다. 메소드 구현은 문제가 아닙니다. 메소드 * 시그니처 *가 있습니다. – Manav

+0

@KnickerKicker : 두 번째 단락을 고려해보십시오. 바이트를 직접 long으로 읽거나 long –

+0

을 가진 유니온의 일부인 char [4]로 읽으십시오. 시도해 볼 것입니다.덕분에 :) 어쨌든, 왜 컴파일러가 그 일을하는지, 그리고 모든 컴파일러가 그 일을하는지 알겠습니까? – Manav

0

개가 천천히? 실제로 측정 했습니까? 당신은 ntoh32의 스타일을 다시 크게 작업의 수를 줄일 수 있습니다 : ...

테스트 장비 (들여 쓰기를 보존하기 위해 별도의 답변으로이 게시)

uint32_t ntoh_4b(char v[]) 
{ 
    return ((uint32_t)(unsigned char)v[0] << 24) 
     | ((uint32_t)(unsigned char)v[1] << 16) 
     | ((uint32_t)(unsigned char)v[2] << 8) 
     | ((uint32_t)(unsigned char)v[3]  ); 
} 
+0

인 엔디안을 알 수있는 방법이 없다는 것을 알았습니다. : 나중에 프로파일을 시도 할 것입니다. 그러나 느려질 것이라고 생각합니다. 모든 배열 인덱싱으로 인해 ... - 어쨌든, 좋은 * 재 해석 * – Manav

+0

상수 인덱스가있는 char 배열 (sizeof == 1)입니다. 컴파일러 최적화 없이도 번개처럼 빠르지 만, 실제로 병목 현상이 될 때까지는 신경 쓰지 않을 것입니다. 귀하의 버전에는 8 개의 쓰기 및 8 개의 읽기 액세스가있는 임시 변수가 있으며, 내 버전에는 완전히 빠져 있습니다. 내가 그 작전을 의미한다는 것. – Secure

+0

아래 벤치 마크를 참조하십시오. – Manav

0

union { 
     char a[4]; 
     uint32_t i; 
    } t; 
    t.i = 0xaabbccdd; 

    uint32_t v; 
    for (uint32_t i = 0; i < -1; ++i) 
    { 
     //v = ntohl (t.i); (1) 
     //v = ntoh32 (t.i); (2) 
     //v = ntoh_4b (t.a); (3) 
    } 

ntoh32의 분해 ...

movl %edi, -4(%rbp) 
movl -4(%rbp), %eax 
movl %eax, %edx 
sall $24, %edx 
movl -4(%rbp), %eax 
andl $65280, %eax 
sall $8, %eax 
orl %eax, %edx 
movl -4(%rbp), %eax 
andl $16711680, %eax 
shrl $8, %eax 
orl %eax, %edx 
movl -4(%rbp), %eax 
shrl $24, %eax 
orl %edx, %eax 
leave 

ntoh_4b의 분해 ...

movq %rdi, -8(%rbp) 
movq -8(%rbp), %rax 
movzbl (%rax), %eax 
movzbl %al, %eax 
movl %eax, %edx 
sall $24, %edx 
movq -8(%rbp), %rax 
addq $1, %rax 
movzbl (%rax), %eax 
movzbl %al, %eax 
sall $16, %eax 
orl %eax, %edx 
movq -8(%rbp), %rax 
addq $2, %rax 
movzbl (%rax), %eax 
movzbl %al, %eax 
sall $8, %eax 
orl %eax, %edx 
movq -8(%rbp), %rax 
addq $3, %rax 
movzbl (%rax), %eax 
movzbl %al, %eax 
orl %edx, %eax 
leave 

그리고 마지막으로 결과입니다. 비교를위한 기준을 제공하기 위해 C 라이브러리의 ntohl을 포함 시켰습니다.

//v = ntohl (t.i); (1) 
real 0m35.030s 
user 0m34.739s 
sys 0m0.245s 

//v = ntoh32 (t.i); (2) 
real 0m36.272s 
user 0m36.070s 
sys 0m0.115s 

//v = ntoh_4b (t.a); (3) 
real 0m40.162s 
user 0m40.013s 
sys 0m0.097s