C++ 将浮点转换为字节数组的程序中的运行时错误
我得到了一个浮点变量,想知道它的字节表示是什么。所以我去了IDEOne,并且这样做了。但是,令我惊讶的是,它会导致运行时错误:C++ 将浮点转换为字节数组的程序中的运行时错误,c++,c,floating-point,unions,C++,C,Floating Point,Unions,我得到了一个浮点变量,想知道它的字节表示是什么。所以我去了IDEOne,并且这样做了。但是,令我惊讶的是,它会导致运行时错误: #include <stdio.h> #include <assert.h> int main() { // These are their sizes here. So just to prove it. assert(sizeof(char) == 1); assert(sizeof(short) == 2);
#include <stdio.h>
#include <assert.h>
int main()
{
// These are their sizes here. So just to prove it.
assert(sizeof(char) == 1);
assert(sizeof(short) == 2);
assert(sizeof(float) == 4);
// Little endian
union {
short s;
char c[2];
} endian;
endian.s = 0x00FF; // would be stored as FF 00 on little
assert((char)endian.c[0] == (char)0xFF);
assert((char)endian.c[1] == (char)0x00);
union {
float f;
char c[4];
} var;
var.f = 0.0003401360590942204;
printf("%x %x %x %x", var.c[3], var.c[2], var.c[1], var.c[0]); // little endian
}
在IDEOne上,它输出:
39 FFFFFF B2 54 4a
以及一个运行时错误。为什么会出现运行时错误,为什么b2实际上是FFFFFF b2?我猜b2是符号扩展。字符是有符号类型。如果它的长度为8位,并且您在其中放入大于127的任何内容,它将溢出。有符号整数溢出是未定义的行为,因此,使用转换说明符打印有符号值时,该说明符应为无符号整数%x应为无符号整数,但在传递给变量printf函数时,char被提升[隐式转换]为有符号整数
底线-将char c[4]更改为unsigned char c[4],它将正常工作。在结构中用unsigned char替换char,并添加一个返回0;最后解决了所有问题:。你的方法完全错误。以下是如何打印常规对象的二进制表示:
template <typename T>
void hexdump(T const & x)
{
unsigned char const * p = reinterpret_cast<unsigned char const *>(&x);
for (std::size_t i = 0; i != sizeof(T); ++i)
{
std::printf("%02X", p[i]);
}
}
结果是,您始终可以将任何对象解释为字符数组,从而显示其表示形式。为什么需要返回0?我认为标准说它是可选的,编译器必须隐式地添加它?有没有解释为什么会这样做?@ColeJohnson AFAIK这是我们应该使用的C99。返回0;在C89中不是隐式的。未签名的问题由@H2CO3完美地解释了。作为回报,这是我第一次使用ideone.com,我不知道他们使用的是哪个C以及如何配置它。所以这只是一个猜测。抱歉。打印FFFFFF B2是因为vats.c[2]是字符,这是一种有符号的数据类型。printf将符号扩展为32位整数,因为varargs就是这样做的。您可以将其声明为无符号字符c[4]或在printf中强制转换。您是否注意到有效位数超出了限制?还可以在文字上使用“f”后缀,以指定浮点而不是双精度为什么FFFFFF b2而不是您猜测的b2是符号扩展名。但是运行时错误呢?我希望你贴出它的确切原因。符号v。unsigned、no\n、not return等@notNullGothik将值0.000340130160590942204分配给var.f时转换为float。除非您怀疑这个数字容易出现双舍入,否则在文本中添加f后缀没有什么意义。如前所述,var.c[i]在传递到printf时会升级为int,因为这是可变函数的工作方式。但是%x格式需要一个对应的无符号int。因此,除了使用一个无符号字符数组(每个字符仍将升级为int,因为C就是这样工作的),您应该调用printf%x%x%x,unsigned int var.C[3],…C99 5.2.4.2.1 p2说字符可能是有符号的,也可能是无符号的。它是实现定义的。6.3.1.1 p3中有更明确的说明:如前所述,“普通”字符是否被视为有符号字符是由实现定义的。“有符号整数溢出是未定义的行为”->在这个问题中哪里有未定义的溢出?转换为有符号类型时的溢出是由实现定义的。我没有看到任何其他类型的溢出。@PascalCuoq说是UB。也许是C++中的IB?@ H2CO3“符号整数溢出是UB”通常是正确的,但它缺乏细微差别。我不认为对于如此长度的句子,它尽可能准确,但细节是,到有符号类型的转换实际上是实现定义的。您链接的问题是32位编译器上的算术溢出,例如0x10000*0x10000。我在这个问题中看到的唯一溢出是char0xFF,大多数签名为8位char的实现都将其定义为char-1。在C99中,这是在6.3.1.3:3中。@PascalCuoq谢谢,我来看看那个子句。