【问题标题】:Efficient conversion of float endianness in strict portable C严格可移植 C 中浮点字节序的有效转换
【发布时间】:2018-04-30 02:26:36
【问题描述】:

使用this answer 很好,因为它非常便携、正确并通过了严格设置的编译器,但它的效率比我想要的要低,因为它不使用 x86 bswap 指令。 (也许其他指令集也有类似的高效指令。)

如果我运行的系统支持ntohl(),那么我希望ntohl() 使用bswap 指令并让我接近。 ntohl() 完全正确,但它只适用于 uint32_t,而不适用于浮点数。 uint32_t 和浮点数之间的转换是类型双关语,严格的编译器不允许。使用浮点数和 uint32_t 进行联合会遇到未定义的编译器行为(根据此处的先前帖子)。

我从以前的帖子中了解到,明确允许从任何指针类型转换为 char * 或反之亦然。那么这个解决方案有什么问题呢?我还没有看到任何答案中提到它。

char NetworkOrderFloat[4]; // Assume it contains network-order float bytes

uint32_t HostOrderInt = ntohl(*(uint32_t *)NetworkOrderFloat);

char *Pointer = (char *)&HostOrderInt;

float HostOrderFloat = *(float *)Pointer;

这里的理想解决方案似乎是更多支持ntohf() 的环境,但这似乎还没有发生。

【问题讨论】:

  • “使用浮点数和 uint32_t 进行联合会遇到未定义的编译器行为(根据此处之前的帖子)”并非如此,它在 C99TC3 中添加并保留在后来的 C 标准中的脚注 82 明确允许.这肯定是实现定义的行为。
  • “使用浮点数和 uint32_t 进行联合会遇到未定义的编译器行为(根据此处之前的帖子)”对于此处标记的 C 来说不是问题。之前的那篇文章是 C++ 的,联合是一个问题。
  • 当浮点表示不能保证可移植时,严格可移植的意义何在?
  • @YvesDaoust:具有一个约束(实现必须使用 IEEE-754)的代码比具有两个约束(实现必须使用 IEEE-754 并且必须是 little-endian)的代码更易于使用。

标签: c optimization floating-point endianness


【解决方案1】:

您的提案违反了“严格的别名规则”,这是它第一次违反 *(uint32_t *)NetworkOrderFloat。表达式(uint32_t *)NetworkOrderFloat 仍然是字符数组的地址,使用uint32_t 类型的左值访问它是违反这些规则的。详细信息和更多示例可以在this article中找到。

另一方面,据我所知,C 标准并不禁止使用union 将浮点表示转换为uint32_t。但是,如果您担心,可以随时使用memcpy

float NetworkOrderFloat = ...;
uint32_t tmp;
_Static_assert(sizeof(uint32_t)==sizeof(float),"unsupported arch");
memcpy(&tmp, &NetworkOrderFloat, sizeof(float));
tmp = ntohl(tmp);
memcpy(&HostOrderFloat, &tmp, sizeof(float));

一个体面的现代编译器should compile memcpy 什么都不调用,ntohl 调用 bswap

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    • 2012-05-24
    • 2014-02-22
    • 1970-01-01
    • 1970-01-01
    • 2017-03-25
    相关资源
    最近更新 更多