我需要一个短的值从主机字节顺序转换成小端。如果目标是大端,我可以使用htons()函数,但很可惜 - 这不是

我想我可以做的:

swap(htons(val))

但是,这有可能导致字节被换两次,渲染后的结果正确的,但给我的性能损失这是不是在我的情况好了。

有帮助吗?

解决方案

类似如下:

unsigned short swaps( unsigned short val)
{
    return ((val & 0xff) << 8) | ((val & 0xff00) >> 8);
}

/* host to little endian */

#define PLATFORM_IS_BIG_ENDIAN 1
#if PLATFORM_IS_LITTLE_ENDIAN
unsigned short htoles( unsigned short val)
{
    /* no-op on a little endian platform */
    return val;
}
#elif PLATFORM_IS_BIG_ENDIAN
unsigned short htoles( unsigned short val)
{
    /* need to swap bytes on a big endian platform */
    return swaps( val);
}
#else
unsigned short htoles( unsigned short val)
{
    /* the platform hasn't been properly configured for the */
    /* preprocessor to know if it's little or big endian    */

    /* use potentially less-performant, but always works option */

    return swaps( htons(val));
}
#endif

如果您有配置正确的系统(如预处理器知道是否该目标识别很少或大端)你htoles()的“优化”的版本。否则,你得到的可能非优化的版本取决于htons()。在任何情况下,你会得到一些作品。

没有什么太棘手和更多或更少的便携式的。

当然,可以进一步通过你认为合适的与inline或作为宏实现此改善优化的可能性。

您可能想看看像“手提开源线束(POSH)”为实际的实现,它定义了各种编译器的存储方式。注意,让图书馆需要去虽然是伪认证页面(虽然你并不需要注册提供任何个人信息)的 http://hookatooka.com/poshlib/

其他提示

下面是字节排列顺序以及如何从IBM确定它的制品:

C编写尾数无关的代码:别让字节顺序“字节”你

它包括如何确定在运行时字节序(你只需要做一次)的示例

const int i = 1;
#define is_bigendian() ( (*(char*)&i) == 0 )

int main(void) {
    int val;
    char *ptr;
    ptr = (char*) &val;
    val = 0x12345678;
    if (is_bigendian()) {
        printf(“%X.%X.%X.%X\n", u.c[0], u.c[1], u.c[2], u.c[3]);
    } else {
        printf(“%X.%X.%X.%X\n", u.c[3], u.c[2], u.c[1], u.c[0]);
    }
    exit(0);
}

在页面还对用于反转字节顺序方法部分:

short reverseShort (short s) {
    unsigned char c1, c2;

    if (is_bigendian()) {
        return s;
    } else {
        c1 = s & 255;
        c2 = (s >> 8) & 255;

        return (c1 << 8) + c2;
    }
}

short reverseShort (char *c) {
    short s;
    char *p = (char *)&s;

    if (is_bigendian()) {
        p[0] = c[0];
        p[1] = c[1];
    } else {
        p[0] = c[1];
        p[1] = c[0];
    }

    return s;
}

那你应该知道你的字节顺序和条件调用htons()。其实,即使没有htons,只是交换条件字节。编译时,当然。

此特技应该将:在启动时,使用ntohs与虚设值,然后将所得值与原始值。如果这两个值相同,则该机采用大端,否则它是小端。

然后,使用ToLittleEndian方法,要么不执行任何操作或调用ntohs,取决于初始测试的结果。

(在评论提供的信息编辑)

我的原则进行的拇指性能的猜测是,要看你是否是小端 - 伊辛一气呵成,或只是一个值的数据的大块:

如果只有一个值,则函数调用的开销很可能将淹没不必要的字节交换的开销,那就是即使编译器不优化掉不必要的字节交换。然后,你可能会写值作为套接字连接的端口号,并尝试打开或绑定套接字,这需要一个年龄与任何种类的位操作进行了比较。所以,只是不担心。

如果一个大块,那么你可能会担心,编译器不会处理它。所以,做这样的事情:

if (!is_little_endian()) {
    for (int i = 0; i < size; ++i) {
        vals[i] = swap_short(vals[i]);
    }
}

或可考虑在你的架构的SIMD指令可以做到这一点相当快。

使用任何你喜欢的把戏写is_little_endian()。我认为,一个罗伯特·S·巴恩斯提供的是完善的,但因为你通常都知道对于一个给定的目标是否将是大端或小端,也许你应该有一个平台特定的头文件,它定义它是一个宏评估要么为1或0。

当然,如果你真的在乎性能的话,看生成的汇编,看毫无意义的代码是否已被删除或没有,时间对彼此的各种替代方案,看看什么是真正进入最快的。

不幸的是,不是一个真正的跨平台的方式在编译时有标准C.我建议增加一个#defineconfig.h(或任何你或你的构建系统用于构建配置),以确定系统的字节顺序。

一个单元测试,以检查LITTLE_ENDIANBIG_ENDIAN的正确定义可能看起来像这样:

#include <assert.h>
#include <limits.h>
#include <stdint.h>

void check_bits_per_byte(void)
{ assert(CHAR_BIT == 8); }

void check_sizeof_uint32(void)
{ assert(sizeof (uint32_t) == 4); }

void check_byte_order(void)
{
    static const union { unsigned char bytes[4]; uint32_t value; } byte_order =
        { { 1, 2, 3, 4 } };

    static const uint32_t little_endian = 0x04030201ul;
    static const uint32_t big_endian = 0x01020304ul;

    #ifdef LITTLE_ENDIAN
    assert(byte_order.value == little_endian);
    #endif

    #ifdef BIG_ENDIAN
    assert(byte_order.value == big_endian);
    #endif

    #if !defined LITTLE_ENDIAN && !defined BIG_ENDIAN
    assert(!"byte order unknown or unsupported");
    #endif
}

int main(void)
{
    check_bits_per_byte();
    check_sizeof_uint32();
    check_byte_order();
}

在许多Linux系统,有一个或<endian.h><sys/endian.h>转换功能。对于ENDIAN 手册页(3)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top