오픈 소스 program I wrote에서는 파일에서 다른 프로그램으로 작성된 이진 데이터를 읽고 ints, double, 및 기타 여러 가지 데이터 유형을 출력합니다. 문제 중 하나는 이 양쪽 endiannesses의 32 비트 및 64 비트 시스템에서 실행되어야한다는 것입니다. 즉, 은 저수준 비트 twiddling을 꽤 많이 수행해야합니다. 나는 (매우) 약간의 punning과 엄격한 앨리어싱에 대해서 알고 있으며, 내가 올바르게 일을하는지 확인하고 싶다.안전하게 COOL에서 char *를 두들겨 쓰는 방법 *
기본적으로, 다양한 크기의 int로 숯불 * 변환을 쉽게 :
int64_t snativeint64_t(const char *buf)
{
/* Interpret the first 8 bytes of buf as a 64-bit int */
return *(int64_t *) buf;
}
하고 필요에 따라 나는 그런 로, 바이트 순서를 교환하는 지원 기능의 캐스팅이 있습니다
런타임시int64_t swappedint64_t(const int64_t wrongend)
{
/* Change the endianness of a 64-bit integer */
return (((wrongend & 0xff00000000000000LL) >> 56) |
((wrongend & 0x00ff000000000000LL) >> 40) |
((wrongend & 0x0000ff0000000000LL) >> 24) |
((wrongend & 0x000000ff00000000LL) >> 8) |
((wrongend & 0x00000000ff000000LL) << 8) |
((wrongend & 0x0000000000ff0000LL) << 24) |
((wrongend & 0x000000000000ff00LL) << 40) |
((wrongend & 0x00000000000000ffLL) << 56));
}
, 프로그램은 시스템의 엔디안 니스를 검출하고 함수 포인터 위의 을 대입
012,308,505,353,이제는 char *를 이중으로 캐스팅하려고 할 때 까다로운 부분이 있습니다.
union
{
double d;
int64_t i;
} int64todouble;
int64todouble.i = slittleint64_t(bufoffset);
printf("%lf", int64todouble.d);
그러나 일부 컴파일러는 "int64todouble.i"할당 을 멀리 최적화 프로그램을 깰 수 : 나는 지금처럼 엔디안 스와핑 코드를 다시 사용하고 싶습니다. 이 프로그램이 성능을 위해 최적화되어 있어야하며, 은 double * 에 char *를 캐스팅하기 위해 병렬 변환 집합을 쓰지 않는 것을 선호한다고 생각하면 안전한 방법이 있습니까? 노조 방법이 안전하다면, snatchint64_t와 같은 함수를 다시 써야합니까?
snativeint64_t:
movq (%rdi), %rax
ret
:
int64_t snativeint64_t(const char *buf)
{
/* Interpret the first 8 bytes of buf as a 64-bit int */
int64_t output;
memcpy(&output, buf, 8);
return output;
}
내 원래의 코드와 똑같은 어셈블러로 컴파일 :
나는 변환 기능을 다시 작성하기 때문에, 방어 적이기를 사용과 같이 할 Steve Jessop's 대답을 사용하여 종료
두 버전 중 memcpy 버전은 내가하려는 일을보다 명확하게 표현하고 가장 순진한 컴파일러에서도 작동해야합니다.
아담, 당신의 대답도 훌륭했고 나는 그것에 대해 많은 것을 배웠습니다. 게시 해 주셔서 감사합니다!
정수 변환은 char 포인터가 충분히 잘 정렬되어있는 경우에만 안전합니다. –
이 프로그램에서, 그것은 항상있을 것입니다. –
런타임에서 엔디안을 전혀 감지하지 못하는 이유는 무엇입니까? 나는이 프로그램이 특정 endian-ness를 가질 컴파일 된 아치에서만 작동 할 수 있다고 상상할 것입니다. 그래서 여러분은 ntohl을 좋아하고 컴파일 시간 결정을 내리지 않습니까? –