无符号u = *(unsigned *)& x的含义是什么?在C++ x在哪里浮动变量?

发布于 2025-02-07 13:38:03 字数 182 浏览 1 评论 0原文

由于我的数值分析课程考试即将到来,所以我正在寻找一个实现代码以表示C/C ++中的浮点数?然后,我从Github中的代码中找到了一条线。您能告诉我,下面的代码段中第二行的含义是什么,以及为什么这很重要?

float x = ...;
unsigned u = *(unsigned*)&x; 

Since my Numerical Analysis course exam is near, I was searching for a implementation code to to represent floating point numbers in C/C++? Then I found a line from one the codes in github. Can you please tell me, what is the meaning of the second line in the code snippet below, and how and why this is important?

float x = ...;
unsigned u = *(unsigned*)&x; 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

油饼 2025-02-14 13:38:04

unsigned只是unsigned int的简短,并且使用C ++ - 样式铸造该行将转换为

unsigned int u = *reinterpret_cast<unsigned int*>(&x);

以下内容,但是在下面阅读为什么在任何一种情况下都会导致不确定的行为。

并不明显。

(我建议不要像问题中所示的行中使用C风格的铸件一样,因为C ++的样式 /code>变量,然后该行试图重新解释float变量的对象表示为nosigned int的对象表示,基本上是重新诠释float的内存为intemed int的内存,然后存储insted int值,在u中与该表示相对应的值。

步骤的步骤,&amp; xx type float*的指针; x)是指向x的指针,但现在类型为intemed> intemed int*。然后*reinterpret_cast&lt; unsigned int*&gt;(&amp; x)应该解释int unsigned int*指针指向float float变量,从指向内存的位置检索inted int值,好像在其中存储的字节代表无符号int值,而不是float值。最后,unsigned int u =应该使用该值来初始化u

这会导致不确定的行为,因为它是通过float对象通过无符号的INT*指针访问float对象。一些编译器具有可以允许此功能的选项(在floatunsigned Int具有兼容大小和对齐方式的假设下),但是标准C ++不允许使用。语言本身。

通常,每当您看到reinterpret_cast(或可能解析为reinterpret_cast)的C风格铸件时,如果您不知道确切的情况,您可能会导致不确定的行为你在做。


由于C ++ 20在没有未定义行为的情况下执行此操作的正确方法是使用std :: bit_cast

float x = /*...*/;
auto u = std::bit_cast<unsigned>(x);

或者在C ++之前使用std :: memcpy

float x = /*...*/;
unsigned u;
static_assert(sizeof(u) == sizeof(x));
std::memcpy(&u, &x, sizeof(u));

大小验证由std :: bit_cast自动完成。即使没有C ++ 20,也可能是一个好主意,最好将static_assertmemcpy在类似的通用函数中进行重复使用。

这两个仍然都要求x的表示也是u的有效表示。否则,行为仍然不确定。我不知道是否有任何C ++实现,在float-&gt;未签名案例。


另外,请注意:C是另一种语言。例如,规则在C中很可能有所不同。例如,在>(unsigned*) cast可以解决的reinterpret_cast显然没有reinterpret_cast。但是,在这种情况下,C的混叠规则将产生同等效果。

unsigned is just short for unsigned int and using C++-style casts the line would translate to

unsigned int u = *reinterpret_cast<unsigned int*>(&x);

However read below why this causes undefined behavior in either case.

(I recommend to not use C-style casts as in the line shown in the question, since it is not obvious to which C++-style cast they resolve.)

If x is a float variable, then the line is trying to reinterpret the object representation of the float variable as the object representation of an unsigned int, basically to reinterpret the float's memory as the memory of an unsigned int, and then stores the unsigned int value corresponding to that representation in u.

Step for step, &x is a pointer to x of type float*, reinterpret_cast<unsigned int*>(&x) is a pointer to x, but now of type unsigned int*. And then *reinterpret_cast<unsigned int*>(&x) is supposed to dereference that unsigned int* pointer to the float variable to retrieve an unsigned int value from the pointed-to memory location as if the bytes stored there represented an unsigned int value instead of a float value. Finally unsigned int u = is supposed to use that value to initialize u with it.

That causes undefined behavior because it is an aliasing violation to access a float object through a unsigned int* pointer. Some compilers have options which can be enabled to allow this (under the assumption that float and unsigned int have compatible size and alignment), but it is not permitted by the standard C++ language itself.

Generally, whenever you see reinterpret_cast (or a C-style cast that might resolve to a reinterpret_cast), you are likely to cause undefined behavior if you don't know exactly what you are doing.


Since C++20 the correct way to do this without undefined behavior is using std::bit_cast:

float x = /*...*/;
auto u = std::bit_cast<unsigned>(x);

or before C++20 using std::memcpy:

float x = /*...*/;
unsigned u;
static_assert(sizeof(u) == sizeof(x));
std::memcpy(&u, &x, sizeof(u));

The size verification is done by std::bit_cast automatically. Even without C++20 it would probably be a good idea to wrap the static_assert and memcpy in a similar generic function for reuse.

Both of these still require that the representation of x is also a valid representation for a u. Otherwise the behavior is still undefined. I don't know whether there even is any C++ implementation where this doesn't hold for all values in the float -> unsigned case.


Also as an additional note: C is a different language. The rules may well be different in C. For example there is obviously no reinterpret_cast in C to which the (unsigned*) cast could resolve and the object model is very different. In this case though, C's aliasing rules will have an equivalent effect.

为你拒绝所有暧昧 2025-02-14 13:38:04

它不是有效的C ++。 (程序的行为)是未定义的。
演员表的表达将导致违反一致性要求(又称“严格的违反违约”)。
请参阅:§6.7内存和对象§6.8类型 iso/iec JTC1 SC22 WG21

问题是显式铸造将成为reinterpret_cast

float boat = 420.69f;
// unsigned dont_do_this = * reinterpret_cast<unsigned *> (&boat);
//          ~~~~~~~~~~~~~~~^
//  Dereferencing `unsigned*` pointer which doesn't point to an `unsigned`.

float*不是 使用无符号*
您可以做到这一点:

auto since_cpp20 = std::bit_cast<unsigned>(boat); // include <bit>
// Alternatively:
unsigned since_c;
std::memcpy(&since_c, &boat, sizeof since_c);

It is not valid C++. The behavior (of the program) is undefined.
The cast expression would cause the alignment requirement to be violated (aka "strict aliasing violation").
See: §6.7 Memory and objects, and §6.8 Types of ISO/IEC JTC1 SC22 WG21.

The problem is the explicit cast will become a reinterpret_cast:

float boat = 420.69f;
// unsigned dont_do_this = * reinterpret_cast<unsigned *> (&boat);
//          ~~~~~~~~~~~~~~~^
//  Dereferencing `unsigned*` pointer which doesn't point to an `unsigned`.

float* is not Pointer-Interconvertible with unsigned*.
You could do this, instead:

auto since_cpp20 = std::bit_cast<unsigned>(boat); // include <bit>
// Alternatively:
unsigned since_c;
std::memcpy(&since_c, &boat, sizeof since_c);
失眠症患者 2025-02-14 13:38:04

假设xfloat,那么代码是一种hack的方法,可以通过将其钻头直接复制到整数中,即无需执行正常浮动而访问浮子的二进制格式指向整数转换,如果您只是写u = x;,将会发生。

Assuming that x is float, then the code is a hacky way to access the binary format of a float by copying its bits directly to an integer, i.e. without doing the normal floating point to integer conversion that would happen if you just wrote u = x;

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文