重新Interalpret_cast浮动整数是安全的吗?
Is it safe to reinterpret_cast an integer to float?
注意:我最初错误地询问了有关static_cast
的问题;这就是为什么首先提到static_cast
的原因。
我有一些二进制文件,却很少。我想以与机器无关的方式阅读它们。我的字节交换例程(来自SDL)在未签名的整数类型上运行。
简单地在ints和floats之间施放安全吗?
float read_float() {
// Read in 4 bytes.
Uint32 val;
fread( &val, 4, 1, fp );
// Swap the bytes to little-endian if necessary.
val = SDL_SwapLE32(val);
// Return as a float
return reinterpret_cast<float &>( val ); //XXX Is this safe?
}
我希望该软件尽可能便携。
好吧, static_cast
是"安全的",它已经定义了行为,但这可能不是您需要的。将积分值转换为浮点类型将只是尝试在目标浮点类型中表示相同的积分值。IE。int
类型的5
将变成float
类型的5.0
(假设它是可以准确表示的)。
您似乎正在做的是在将float
值的对象表示形式构建为Uint32
变量的一段记忆中。要产生所得的float
值,您需要 retontret 该内存。这将由reinterpret_cast
assert(sizeof(float) == sizeof val);
return reinterpret_cast<float &>( val );
或,如果您喜欢的,则是同一物品的指针版
assert(sizeof(float) == sizeof val);
return *reinterpret_cast<float *>( &val );
尽管不能保证这种类型的类型能够在严格启用语义的编译器中起作用。另一种方法是这样做
float f;
assert(sizeof f == sizeof val);
memcpy(&f, &val, sizeof f);
return f;
,否则您可能能够使用著名的联合骇客来实现内存重新诠释。在C (未定义的行为)中,这是正式非法的,这意味着该方法只能与某些实现一起使用,以将其作为扩展名
assert(sizeof(float) == sizeof(Uint32));
union {
Uint32 val;
float f;
} u = { val };
return u.f;
简而言之,这是不正确的。您正在将整数投放到浮子上,并将其解释为当时的整数。上面提出的工会解决方案。
另一种做与联盟相同的事情的方法是使用它:
return *reinterpret_cast<float*>( &val );
它与上面的联合解决方案同样安全/不安全,我绝对建议一个断言,以确保浮子的大小与int相同。
我还要警告说,有一些不是IEEE-754或IEEE-854兼容的浮点格式(这两个标准具有相同的浮点数格式,我不完全确定该细节差异是什么诚实的)。因此,如果您有一台使用不同浮点格式的计算机,则它将掉落。我不确定是否有任何方法可以检查一下,除了将罐装字节存储在某个地方,以及浮动中的预期值之外,然后转换值并查看是否出现"正确"。
(正如其他人所说的那样,重新诠释的铸件,基础内存被对待,好像是另一种类型,是不确定的行为/放置在记忆中。)
这是ANT的Memcpy解决方案的模板实现,该解决方案避免了-Wstrict-aliasing
警告。
我猜这支持了大小不是标准尺寸的实现,但仍然匹配模板大小之一 - 然后如果没有匹配项,则无法编译。
(使用-fstrict-aliasing -Wall
编译实际启用-Wstrict-aliasing
)
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <type_traits>
template<size_t S> struct sized_uint;
template<> struct sized_uint<sizeof(uint8_t)> { using type = uint8_t; };
template<> struct sized_uint<sizeof(uint16_t)> { using type = uint16_t; };
template<> struct sized_uint<sizeof(uint32_t)> { using type = uint32_t; };
template<> struct sized_uint<sizeof(uint64_t)> { using type = uint64_t; };
template<size_t S> using sized_uint_t = typename sized_uint<S>::type;
template<class T> sized_uint_t<sizeof(T)> bytesAsUint(T x)
{
sized_uint_t<sizeof(T)> result;
// template forces size to match. memcpy handles alignment
memcpy(&result, &x, sizeof(x));
return result;
}
template<size_t S> struct sized_float;
template<> struct sized_float<sizeof(float)> { using type = float; };
template<> struct sized_float<sizeof(double)> { using type = double; };
template<size_t S> using sized_float_t = typename sized_float<S>::type;
template<class T> sized_float_t<sizeof(T)> bytesAsFloat(T x)
{
sized_float_t<sizeof(T)> result;
memcpy(&result, &x, sizeof(x));
return result;
}
// Alt for just 'float'
//template<class T> std::enable_if_t<sizeof(T) == sizeof(float), float> bytesAsFloat(T x)
//{
// float result;
// memcpy(&result, &x, sizeof(x));
// return result;
//}
float readIntAsFloat(uint32_t i)
{
// error: no matching function for call to 'bytesAsFloat(uint16_t)'
//return bytesAsFloat((uint16_t)i);
return bytesAsFloat(i);
}
void printFloat(float f) {
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
//printf("Float %f: %x", f, reinterpret_cast<unsigned int&>(f));
printf("Float %f: %x", f, bytesAsUint(f));
}
(Godbolt)
- 线程安全整数数组?
- 哪些整数操作不安全
- 单调计数整数的比较安全吗?
- 将整数添加到数组值而无需调用它的最安全方法
- 哪种整数类型可以安全且便携式用于始终保持指针值
- 使用具有不同整数类型的 std::vector 是否始终安全<size_t>?
- "auto"对 C++17 中的整数溢出是否安全?
- 一个整数可以安全阅读,而另一个线程可能会在其中编写
- 重新Interalpret_cast浮动整数是安全的吗?
- 将负整数与size_t一起使用是否安全
- 将常量字符数组转换为标头中的整数是否始终安全
- 需要一个支持 16 位整数 (c++) 的免费线程安全矩阵数学库
- 将长整数转换为字符数组的最安全方法是什么
- 依靠任何数字类型(无符号、整数等)的隐式提升来加倍是否安全
- 如果使用无符号整数,则通过减去1将基于1的编号转换为基于0的编号是否安全
- 转换枚举中整数的安全方法
- 有没有一种安全的方法可以在不触发溢出的情况下获得有符号整数的无符号绝对值
- 安全派生指针的整数表示形式
- 为什么是同步安全整数
- 科学记数法对C中的整数常数安全吗