简体   繁体   English

从指针值赋值

[英]assigning from a pointer value

I saw the following piece of code in an opensource AAC decoder,我在开源 AAC 解码器中看到了以下一段代码,

static void flt_round(float32_t *pf)
{
    int32_t flg;
    uint32_t tmp, tmp1, tmp2;

    tmp = *(uint32_t*)pf;
    flg = tmp & (uint32_t)0x00008000;
    tmp &= (uint32_t)0xffff0000;
    tmp1 = tmp;
    /* round 1/2 lsb toward infinity */
    if (flg)
    {
        tmp &= (uint32_t)0xff800000;       /* extract exponent and sign */
        tmp |= (uint32_t)0x00010000;       /* insert 1 lsb */
        tmp2 = tmp;                             /* add 1 lsb and elided one */
        tmp &= (uint32_t)0xff800000;       /* extract exponent and sign */

        *pf = *(float32_t*)&tmp1 + *(float32_t*)&tmp2 - *(float32_t*)&tmp;
    } else {
        *pf = *(float32_t*)&tmp;
    }
}

In that the line,在那条线上,

*pf = *(float32_t*)&tmp;

is same as,是一样的,

*pf = (float32_t)tmp;

Isn't it?不是吗?

Or is there a difference?或者有什么区别? Maybe in performance?也许在性能上?

Thank you.谢谢你。

No, they're completely different.不,它们完全不同。 Say the value of tmp is 1. Their code will give *pf the value of whatever floating point number has the same binary representation as the integer 1. Your code would give it the floating point value 1.0!假设tmp值为 1。他们的代码会给*pf任何与整数 1 具有相同二进制表示的浮点数的值。你的代码会给它浮点值 1.0!

This code is editing the value of a float knowing it is formatted using the standard IEEE 754 floating representation .此代码正在编辑浮点值,知道它是使用标准 IEEE 754 浮点表示进行格式化的。

*(float32_t*)&tmp;

means reinterpret the address of temp as being a pointer on a 32 bit float, extract the value pointed.意味着将 temp 的地址重新解释为 32 位浮点数上的指针,提取指向的值。

(float32_t)tmp;

means cast the integer to float 32. Which means 32.1111f may well produce 32 .表示将整数转换为浮点数 32。这意味着32.1111f可能会产生32

Very different.非常不一样。 The first causes the bit pattern of tmp to be reinterpreted as a float .第一个导致tmp的位模式被重新解释为float The second causes the numerical value of tmp to be converted to float (within the accuracy that it can be represented including rounding).第二个导致tmp的数值被转换为float (在它可以表示的精度范围内,包括舍入)。

Try this:尝试这个:

int main(void) {
    int32_t n=1078530011;

    float32_t f;

    f=*(float32_t*)(&n);
    printf("reinterpet the bit pattern of %d as float - f==%f\n",n,f);

    f=(float32_t)n;
    printf("cast the numerical value of %d as float  - f==%f\n",n,f);

    return 0;
}

Example output:示例输出:

reinterpet the bit pattern of 1078530011 as float - f==3.141593
cast the numerical value of 1078530011 as float  - f==1078530048.000000

It's like thinking that就像在想

const char* str="3568";
int a=*(int*)str;
int b=atoi(str);

Will assign a and b the same values.将为ab分配相同的值。

First to answer the question, my_float = (float)my_int safely converts the integer to a float according to the rules of the standard (6.3.1.4).首先回答问题, my_float = (float)my_int根据标准(6.3.1.4)的规则安全地整数转换为浮点数。

When a value of integer type is converted to a real floating type, if the value being converted can be represented exactly in the new type, it is unchanged.当整数类型的值转换为实浮点类型时,如果被转换的值可以准确地表示为新类型,则该值不变。 If the value being converted is in the range of values that can be represented but cannot be represented exactly, the result is either the nearest higher or nearest lower representable value, chosen in an implementation-defined manner.如果要转换的值在可以表示但不能精确表示的值范围内,则结果是最接近的较高或最接近较低的可表示值,以实现定义的方式选择。 If the value being converted is outside the range of values that can be represented, the behavior is undefined.如果被转换的值在可以表示的值范围之外,则行为未定义。

my_float = *(float*)&my_int on the other hand, is a dirty trick, telling the program that the binary contents of the integer should be treated as if they were a float variable, with no concerns at all. my_float = *(float*)&my_int是一个肮脏的技巧,它告诉程序应该将整数的二进制内容视为浮点变量,完全不用担心。

However , the person who wrote the dirty trick was probably not aware of it leading to undefined behavior for another reason: it violates the strict aliasing rule .然而,编写肮脏技巧的人可能没有意识到它导致未定义行为的另一个原因:它违反了严格的别名规则

To fix this bug, you either have to tell your compiler to behave in a non-standard, non-portable manner (for example gcc -fno-strict-aliasing), which I don't recommend.要修复此错误,您必须告诉编译器以非标准、不可移植的方式运行(例如 gcc -fno-strict-aliasing),我不建议这样做。

Or preferably, you rewrite the code so that it doesn't rely on undefined behavior.或者最好重写代码,使其不依赖于未定义的行为。 Best way is to use unions, for which strict aliasing doesn't apply, in the following manner:最好的方法是使用联合,严格别名不适用于以下方式:

typedef union
{
  uint32_t  as_int;
  float32_t as_float;
} converter_t;

uint32_t value1, value2, value3; // do something with these variables

*pf = (converter_t){value1}.as_float + 
      (converter_t){value2}.as_float - 
      (converter_t){value3}.as_float;

Also it is good practice to add the following sanity check:添加以下健全性检查也是一种很好的做法:

static_assert(sizeof(converter_t) == sizeof(uint32_t), 
              "Unexpected padding or wrong type sizes!");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM