C++에서이 C 코드 작업 방법을 알려줄 수 있습니까?유니폼 및 이상한 숫자 형식으로 변환
uint64_t flv_dbl2int(double value)
{
return (union {double f; uint64_t i;}){value}.i;
}
나는 무슨 일이 일어나고 있는지 정확히 알지 못한다.
C++에서이 C 코드 작업 방법을 알려줄 수 있습니까?유니폼 및 이상한 숫자 형식으로 변환
uint64_t flv_dbl2int(double value)
{
return (union {double f; uint64_t i;}){value}.i;
}
나는 무슨 일이 일어나고 있는지 정확히 알지 못한다.
을 "유형 캐스트에 정의되지 않을 수있다", C++에 입력 한 말장난에 대한 유일한 법적 전략은 memcpy()
통해 ,
uint64_t flv_dbl2int(double fvalue)
{
uint64_t ivalue;
memcpy(&ivalue, &fvalue, sizeof ivalue);
return ivalue;
}
reinterpret_cast
uint64_t flv_dbl2int(double value)
{
return reinterpret_cast<uint64_t&>(value);
}
은 실제로 C 스타일 포인터 캐스트를 사용하는 것과 마찬가지로 정의되지 않은 동작입니다.
C에서 합법적 인 반면, 유니온을 사용하면 은 아마도이며 C++에서는 불법입니다. 실제로 이러한 솔루션은 모두 작동 할 가능성이 있으며 적어도 gcc-4.5.3 및 clang-3.0은 x86에서 -O1
에 동일한 코드를 생성합니다.
* 아마도 * C++에서 불법입니다. 다소 모호합니다, 그렇지 않습니까? 나는 C++이 POD의'union '과 같이 제한적이라는 것을 상상할 수 없다. 여기에 관련된 생성자가 없습니다. 반면에, 여러분의 솔루션은 C++에서도'double'과'uint64_t'에 대한 정렬 요구 사항이 다를 수 있기 때문에 * 불법입니다. –
@JensGustedt : 크기가 일치하는 한'memcpy' 메소드는 유효합니다. 두 변수 모두 올바른 정렬을하기 때문에 정렬은 문제가되지 않으며'memcpy'는 바이트를 처리하고 정렬을 신경 쓰지 않습니다. –
@Mike, 아, 미안하지만 충분히 명확하지 않았다. 나는 정렬 문제가있는'reinterpret_cast'를 언급했다. –
이 C99 코드는 익명 공용체를 double
값으로 초기화 한 다음 동일한 메모리를 차지하는 uint64_t
값을 반환합니다. 이것은 double
을 나타내는 "비트"에 도달하는 방법이지만 권장하지는 않습니다.
실제로 마지막으로 작성된 것과 다른 다른 공용 멤버를 읽는 것은 정의되지 않은 동작입니다.
더 좋은 방법은 그냥 포인터 마법을 사용하려면 수 있습니다 :
uint64_t flv_dbl2int(double value)
{
return *((uint64_t *) &value);
}
아니요, 정의되지 않은 동작이 아닙니다. 정의되지 않은 동작입니다. * 읽은 값이 읽는 유형의 트랩 표현 인 경우. 'uint64_t'는 정의에 의해 결코 트랩 표현을 갖지 않습니다. 반면에'double'과'uint64_t'가 다르게 정렬되어 있다면 당신의 버전은 정의되지 않은 동작을 할 수 있습니다. 그러나 이것은 거의 없습니다. –
@unwind : 당신의 대답은 거꾸로 형식입니다.하지만 유니폼은 추천됩니다 * 포인터 캐스트는 엄격한 앨리어스를 위반하여 정의되지 않은 동작을 호출합니다. – Christoph
이는 uint64_t
로 double
값을 해석 리터럴 화합물을 사용합니다. 이 구문은 C++에서 사용할 수 없습니다. return 문 앞에 union 유형의 임시 변수를 만들고 해당 변수의 i
필드를 반환하십시오.
uint64_t flv_dbl2int(double value)
{
union {double f; uint64_t i;} tmp = { value };
return tmp.i;
}
편집 :이 코멘트에 일부 주장과 같은 C++에서 "불법"의 경우, 가장 좋은 건 extern "C"
로 선언하고 별도의 C (그리고 C++)로 컴파일 아마 컴파일 단위. 어쨌든 이것이 악의적 인 해킹임을 알고 있어야합니다. double
은 64 비트 너비가 보장되지 않습니다. 사용자 (또는 상속 된 코드)가 부동 소수점 값의 개별 부분에만 관심이있는 경우 적절한 함수 frexp
을 사용하십시오.
를 캐스팅하면서
이것은 C에서 확실히 합법적이지만 C++에 대해서는 확실하지 않습니다. 하나의 액티브 멤버 만 있고 표준에서는 * general *에서 다른 멤버를 활성화하기 위해 명시 적 파괴 및 배치가 필요하다고 말합니다. 그러나 그것은 POD 멤버의 * 특정 * 경우에 필요한지는 분명하지 않지만 표준은 필요한 의미를 지정하지 않으므로 내 생각 엔 C++에서 유니온을 통한 해당 유형의 펀킹이 실제로 불법입니다. – Christoph
@christoph 그것 때문에 내 C++ 프로젝트에서 C 코드 조각을 사용하고 싶습니다. 나머지는 괜찮 았어.하지만. –
'i'는 액세스 할 때 초기화되지 않기 때문에 이것은 C++에서 정의되지 않은 동작을합니다. –
그냥 포인터를 사용 기억 : 지금까지 내가 말할 수있는
uint64_t flv_dbl2int(double value)
{
union Foo {double f; uint64_t i;};
return (*(Foo *)&value).i;
}
당신의 솔루션은 긴장을 푸는 것보다 낫지 않습니다. 'double'과'uint64_t'는 이론적으로 다르게 배열 될 수 있고,'Foo'와 같은 것일 수도 있습니다. –
코드가 무엇인지 모르는 경우 왜 사용 하시겠습니까? –
C 스타일의 캐스트 대신'static_cast <>'를 사용하십시오. – iammilind
이 코드는 C 및 C++ 모두에서 정의되지 않은 동작을 일으킨다 고 생각합니다. – Lundin