在严格的便携式C

时间:2018-04-30 02:26:36

标签: c optimization floating-point endianness

使用this answer是好的,因为它非常便携,正确并且将编译器设置为严格,但它的效率低于我想要的效果,因为它不使用x86 bswap指令。 (也许其他指令集具有类似的有效指令。)

如果我正在运行的系统支持ntohl(),那么我希望ntohl()能够使用bswap指令并让我接近。 ntohl()完全正确,但它只适用于uint32_t,而不适用于浮点数。 uint32_t和float之间的转换是类型惩罚,严格的编译器不允许。使用float和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()的更多环境,但这似乎还没有发生。

1 个答案:

答案 0 :(得分:3)

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

另一方面,使用union将浮点表示转换为uint32_t,据我所知,C标准并未禁止。但是如果您担心它,可以随时使用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