KEEP K.I.S.S.

tk's blog

类型转换及 Type Punning

tk posted @ Mar 17, 2013 06:42:16 PM in C with tags type punning strict aliasing rule , 3461 阅读

 

将一个 float 类型的值转换为网络字节序,该如何做?

除了手动编码转换外,我们知道 htonl 是将一个32bit无符号整数转换为网络字节序,而 float 也是32bit,那么只要能将一个 float 类型的值转换为bit位相同的 uint32 值,之后再同样转换回 float 就应该可以了。

一般我们会想到利用指针强制类型转换来迫使编译器重新解释指针指向的内存:

float hton_f(float value)
{
    int tmp = htonl(*(unsigned int *)&value);
    return *(float *)&tmp;
}

指针存储的是内存中的地址,地址上的内容由指针类型来解释。这种强制类型转换的技巧叫做 Type punning . 事实上,这种方法存在隐患。

Type punning
A form of pointer aliasing where two pointers and refer to the same location in memory but represent that location as different types. The compiler will treat both "puns" as unrelated pointers. Type punning has the potential to cause dependency problems for any data accessed through both pointers.

多数时候,Type punning 并不会引起任何问题。虽然在 C 标准中它属于依赖实现的实现,但通常可以正常工作。[参考*]

当打开 GCC 的编译选项 -fstrict_aliasing (优化选项 -O2 等会默认打开这个选项)时,则有可能出现问题。编译器认定两种不同类型(signed/unsigned不影响,还有 char *void * 是例外)的指针不会指向同一内存地址,它们之间也没有依赖关系,这种认定下编译器可以对程序进行优化,比如会将不同类型的指针进行操作的代码的顺序(编译的机器码)打乱。而如果这两种类型指针事实上指向同一位置,那么程序代码的执行结果可能会出乎意料(执行顺序跟代码中的顺序不一致)。这种规则也称之为 strict aliasing rule .

一个可以使用的解决方法是使用 union 来进行转换:

float hton_f(float value)
{
    union tagFTOI { 
        float f;
        unsigned int i;
    };
    ((union tagFTOI *)&value)->i = htonl(((union tagFTOI *)&value)->i);               
    return ((union tagFTOI *)&value)->f;
}

除了这种指针写法外,还可以用值方法,就是临时定义一个 union 对象,然后进行赋值转换。

根据 C 标准,任何使用 type punning 的行为依赖编译器实现。那么根据“标准”来看,使用 union 也不是一定能解决问题。标准中规定,设置了 union 中的某个域的值,那么就应该在相同的域读回。

但是大多数编译器都支持使用 union 来进行 type punning 而不破坏 strict aliasing rule . 比如 GCC,GCC 文档中写道:

The practice of reading from a different union member than the one most recently written to (called “type-punning”) is common. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type.

strict aliasing rule 有两个例外,char *void * 指针,举个栗子,用代码实现 float 的绝对值函数:[来源*]

float funky_float_abs (float *a)
{
    float temp_float = *a;
    // valid, because it's a char pointer. These are special.
    unsigned char * temp = (unsigned char *) a;
    temp[3] &= 0x7f;
    return temp_float;
}

float funky_float_abs (float *a)
{
    int temp_int i;
    float temp_float result;
    // Memcpy takes void pointers, so it will force aliasing as well.
    memcpy (&i, a, sizeof (int));
    i &= 0x7fffffff;
    memcpy (&result, &i, sizeof (int));
    return result;
}

上面两个函数都可以正常工作而不违反 strict aliasing rule 规则。至于函数怎么实现 float 的绝对值,可以参考 float 通常是如何在计算机上存储的。


参考资料

  1. Type punning.
  2. Type punning isn't funny: Using pointers to recast in C is bad.
  3. "What are the common undefined/unspecified behavior for C that you run into?.
  4. Type-punning and strict-aliasing
  • 无匹配
  • 无匹配
vx13 说:
Mar 18, 2013 04:28:08 AM

说起来,实际中很少听说有考虑 float 的字节序问题的。因为一般的编译器的 float 是遵从 IEEE 的浮点数标准的,不管是大端还是小端,在内存中的存储都是一样的,所以没必要转换。

Avatar_small
tisyang 说:
Mar 18, 2013 09:08:10 AM

@vx13: 事实上还是有影响,http://en.wikipedia.org/wiki/Endianness#Floating-point_and_endianness 所以最好的方法是不要使用二进制来传递浮点数,而是转换为字符串来传递

vx13 说:
Mar 18, 2013 10:01:50 AM

@tisyang:
我觉得是没关系的,那段里也说了,现代的机器上,可以从实用性角度安全地认为浮点数的表示形式是一致的:
“However, on modern standard computers (i.e., implementing IEEE 754), one may in practice safely assume that the endianness is the same for floating point numbers as for integers, making the conversion straightforward regardless of data type. (Small embedded systems using special floating point formats may be another matter however.)”
至于那些罕见的浮点数表达形式,有些机器根本没有所谓的“网络序”,就算是大小端转换也不能完全涵盖:
“Because there have been many floating point formats with no "network" standard representation for them, there is no formal standard for transferring floating point values between heterogeneous systems. ”
我觉得对于这种情况,只能按照具体场景手动处理了。比如,按照精确度需求乘以一个倍率,然后截断,这样,转成整数来传输,另一端除以倍率,还原成浮点数。

jili slot ฟรีเครดิต 说:
Jan 09, 2023 08:16:01 AM

If you don"t mind proceed with this extraordinary work and I anticipate a greater amount of your magnificent blog entries jili slot ฟรีเครดิต

SEO 说:
May 17, 2023 09:22:19 PM

I personally use them exclusively high-quality elements : you will notice these folks during: 토토사이트

SEO 说:
Jun 11, 2023 03:29:23 PM

Thank you very much for this useful article. I like it. 주소모음

SEO 说:
Jun 11, 2023 03:29:36 PM

Thank you very much for this useful article. I like it. 주소모음

sophia 说:
Jun 21, 2023 01:46:14 AM

Great job for publishing such a beneficial web site. Your web log isn't only useful but it is additionally really creative too. 평택출장마사지

sophia 说:
Jun 27, 2023 05:56:00 PM

I havent any word to appreciate this post.....Really i am impressed from this post....the person who create this post it was a great human..thanks for shared this with us. agencia seo

sophia 说:
Jul 15, 2023 07:10:07 PM

I really appreciate this wonderful post that you have provided for us. I assure this would be beneficial for most of the people. Clicksud

sophia 说:
Jul 25, 2023 10:13:25 PM

Im no expert, but I believe you just made an excellent point. You certainly fully understand what youre speaking about, and I can truly get behind that. 우리카지노

sophia 说:
Aug 30, 2023 03:09:23 AM

Hey what a brilliant post I have come across and believe me I have been searching out for this similar kind of post for past a week and hardly came across this. Thank you very much and will look for more postings from you. เว็บแทงบอลดีที่สุดUFABET

Johny 说:
Sep 01, 2023 12:20:07 PM

Very interesting blog. Alot of blogs I see these days don't really provide anything that I'm interested in, but I'm most definately interested in this one. Just thought that I would post and let you know. last minute naar leipzig

sophia 说:
Sep 03, 2023 12:08:25 AM

<p>
I found so many interesting stuff in your blog especially its discussion. From the tons of comments on your articles, I guess I am not the only one having all the enjoyment here! keep up the good work... <a href="https://wm6969.com/">https://wm6969.com/</a></p>

sophia 说:
Sep 04, 2023 04:55:03 PM

I really appreciate this wonderful post that you have provided for us. I assure this would be beneficial for most of the people. AVALIADOR PREMIADO

Johny 说:
Oct 22, 2023 03:11:23 PM

Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon. Big thanks for the useful info. ufabetทางเข้าเล่น

tech 说:
Dec 11, 2023 11:50:10 PM

The next time I read a blog, I hope that it doesn't disappoint me as much as this one. I mean, I know it was my choice to read, but I thought you had something interesting to say. All I hear is a bunch of whining about something that you could fix if you weren't too busy looking for attention. UFABETแทงบอลเว็บแม่


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter