在 ARM 与 Intel 上将 float 强制转换为 unsigned char

发布于 2024-10-13 06:02:33 字数 1164 浏览 9 评论 0原文

当我在 Intel 机器上运行以下 C 代码时...

float f = -512;
unsigned char c;

while ( f < 513 )
{
    c = f;
    printf( "%f -> %d\n", f, c );
    f += 64;
}

...输出如下:

-512.000000 -> 0
-448.000000 -> 64
-384.000000 -> 128
-320.000000 -> 192
-256.000000 -> 0
-192.000000 -> 64
-128.000000 -> 128
-64.000000 -> 192
0.000000 -> 0
64.000000 -> 64
128.000000 -> 128
192.000000 -> 192
256.000000 -> 0
320.000000 -> 64
384.000000 -> 128
448.000000 -> 192
512.000000 -> 0

但是,当我在 ARM 设备(在我的例子中是 iPad)上运行相同的代码时,结果完全不同

-512.000000 -> 0
-448.000000 -> 0
-384.000000 -> 0
-320.000000 -> 0
-256.000000 -> 0
-192.000000 -> 0
-128.000000 -> 0
-64.000000 -> 0
0.000000 -> 0
64.000000 -> 64
128.000000 -> 128
192.000000 -> 192
256.000000 -> 0
320.000000 -> 64
384.000000 -> 128
448.000000 -> 192
512.000000 -> 0

:您可以想象,这种差异可能会在跨平台项目中引入可怕的错误。我的问题是:

  1. 我是否错误地假设将浮点数强制转换为无符号字符会在所有平台上产生相同的结果?

  2. 他可能是编译器问题吗?

  3. 有一个优雅的解决方法吗?

When I run the following C code on an Intel machine...

float f = -512;
unsigned char c;

while ( f < 513 )
{
    c = f;
    printf( "%f -> %d\n", f, c );
    f += 64;
}

...the output is as follows:

-512.000000 -> 0
-448.000000 -> 64
-384.000000 -> 128
-320.000000 -> 192
-256.000000 -> 0
-192.000000 -> 64
-128.000000 -> 128
-64.000000 -> 192
0.000000 -> 0
64.000000 -> 64
128.000000 -> 128
192.000000 -> 192
256.000000 -> 0
320.000000 -> 64
384.000000 -> 128
448.000000 -> 192
512.000000 -> 0

However, when I run the same code on an ARM device (in my case an iPad), the results are quite different:

-512.000000 -> 0
-448.000000 -> 0
-384.000000 -> 0
-320.000000 -> 0
-256.000000 -> 0
-192.000000 -> 0
-128.000000 -> 0
-64.000000 -> 0
0.000000 -> 0
64.000000 -> 64
128.000000 -> 128
192.000000 -> 192
256.000000 -> 0
320.000000 -> 64
384.000000 -> 128
448.000000 -> 192
512.000000 -> 0

As you can imagine, this sort of difference can introduce horrible bugs in cross-platform projects. My questions are:

  1. Was I wrong to assume that coercing a float into an unsigned char would yield the same results on all platforms?

  2. Could his be a compiler issue?

  3. Is there an elegant workaround?

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

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

发布评论

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

评论(3

你的他你的她 2024-10-20 06:02:33

C 标准对于您想要做的事情没有非常严格的规则。这是来自 6.3.1 算术操作数节(特别是 6.3.1.4 实数浮点和整数节)的相关段落:

当实浮点类型的有限值转换为_Bool以外的整数类型时,小数部分被丢弃(即值被截断为零) 。如果整数部分的值不能用整数类型表示,则行为未定义。

关于您所询问的确切案例,甚至还有一个更具体的脚注:

实数浮点类型的值转换为无符号类型时,不需要执行整数类型的值转换为无符号类型时执行的余数运算。因此,可移植实浮点值的范围是(−1, Utype_MAX+1)

您的情况的 UtypeMAX+1256。你的不匹配案例都是负数。截断后,它们仍然为负,并且超出范围 (-1, 256),因此它们牢牢地处于“未定义行为”区域。即使您展示的一些匹配案例(其中浮点数大于或等于256)也不能保证有效 - 您只是运气好而已。

因此,您的编号问题的答案是:

  1. 是的,您错了。
  2. 从某种意义上说,这是一个编译器问题,不同的编译器会给出不同的结果,但由于规范允许它们这样做,所以我不会真正将其称为编译器的错误。
  3. 这取决于你想做什么 - 如果你能更好地解释这一点,那么社区上的某个人几乎肯定能够帮助你。

The C standard doesn't have very hard rules for what you're trying to do. Here's the paragraph in question, from Section 6.3.1 Arithmetic operands (specifically Section 6.3.1.4 Real floating and integer):

When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.

There's even a more specific footnote about the exact case you're asking about:

The remaindering operation performed when a value of integer type is converted to unsigned type need not be performed when a value of real floating type is converted to unsigned type. Thus, the range of portable real floating values is (−1, Utype_MAX+1).

UtypeMAX+1 for your case is 256. Your mismatched cases are all negative numbers. After the truncation, they're still negative and are outside the range (-1, 256), so they're firmly in the 'undefined behaviour' zone. Even some of the matching cases you've shown, where the floating point number is greater than or equal to 256, aren't guaranteed to work - you're just getting lucky.

The answers to your numbered questions, therefore:

  1. Yes, you were wrong.
  2. It's a compiler issue in the sense that your different compilers give different results, but since they're allowed to by the spec, I wouldn't really call that the compiler's fault.
  3. It depends on what you want to do - if you can explain that better, someone on SO community is almost certain to be able to help you out.
深巷少女 2024-10-20 06:02:33

我将回答我自己的问题中的 3,但不会将其标记为已接受的答案。技巧似乎是强制转换中的简单转换:

c = (char) f;

使用 (int) 或 (short) 也可以。我仍然有兴趣找出这个问题的原因在哪里:编译器或处理器。

I'm going to answer to 3 in my own question but will not flag that as the accepted answer. The trick seems to be a simple cast in the coercion:

c = (char) f;

Using (int) or (short) works too. I'm still interested to find out where the cause of this problem lies: compiler or processor.

彻夜缠绵 2024-10-20 06:02:33

您正在处理的具体问题对我来说看起来像是字节顺序。尝试用 c = *((char *)&f + sizeof(float) - 1); 或类似的内容替换一个或另一个实现,以获取浮点数的最后一个字节,并查看是否它与其他平台的结果匹配。

一般来说,行为取决于处理器的字节顺序、字长和浮点功能,以及编译器如何定位这些功能。 ARM 是双端字节序,因此它可能与 IA 字节顺序匹配,也可能不匹配。似乎也没有一般保证一个 C 实现支持与另一个 C 实现相同的浮点格式: Fixed-浮点类型的大小

您在生产代码中使用它吗?我会非常努力地研究为什么需要这样做。其中一种类型可能没有按预期使用。解决方法不会很优雅。

The specific issue you're dealing with looks like endianness to me. Try replacing one or the other implementation with c = *((char *)&f + sizeof(float) - 1); or something similar to get the last byte of the float, and see if it matches the result for the other platform.

In general, the behavior will depend on endianness, word length and floating point capabilities of the processor, and how the compiler targets that. ARM is bi-endian, so it might or might not match IA byte ordering. It seems there's also no general guarantee that one C implementation supports the same floating point format as another: Fixed-size floating point types .

Are you using this in production code? I'd look very hard at why this needs to be done. One or the other type is probably not being used as intended. Workarounds are not going to be elegant.

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