【问题标题】:C/Cygwin: Porting htoll() from macOS/unix to Windows CygwinC/Cygwin:将 htoll() 从 macOS/unix 移植到 Windows Cygwin
【发布时间】:2017-04-12 09:09:38
【问题描述】:

我正在将我的应用程序从 macOS 平台移植到 Windows 平台(这里是 Cygwin)。我遇到了网络功能 ntohll() 和 htonll() 的问题,而 ntohl()/htonl() 和 ntohs()/htons() 似乎工作正常

    /* LACK OF ntohll() function definition on Cygwin */
    // convert int64 from network to host representation
    *int64 = ntohll(network_int64);

    /* SEEMS TO WORK CORRECTLY */
    // convert int32 from network to host representation
    *int32 = ntohl(network_int32);

更新:这个呢?

uint64_t ntohll(uint64_t network_num64) {

    uint32_t network_num32[2];
    uint32_t host_num32[2];
    uint64_t host_num64;

    memcpy(network_num32, &network_num64, sizeof(network_num64));
    host_num32[0] = ntohl(network_num32[0]);
    host_num32[1] = ntohl(network_num32[1]);

    memcpy(&host_num64, host_num32, sizeof(host_num64));
    return host_num64;
}

uint64_t htonll(uint64_t host_num64) {

    uint32_t host_num32[2];
    uint32_t network_num32[2];
    uint64_t network_num64;

    memcpy(host_num32, &host_num64, sizeof(host_num64));
    network_num32[0] = htonl(host_num32[0]);
    network_num32[1] = htonl(host_num32[1]);

    memcpy(&network_num64, network_num32, sizeof(network_num64));
    return network_num64;
}

【问题讨论】:

  • 提示:你可以使用htonl两次创建htonll
  • 你能给我举个例子吗?我应该以某种方式将 uint64_t 数字拆分为 2 个 uint32_t 数字吗?
  • @JonathonReinhart:你确定吗?你怎么知道这两个结果的使用顺序?
  • 是的,这两个数字的顺序有问题;/我更新了这个提示,但我认为它不能正常工作。
  • @JonathanLeffler 假设 __BYTE_ORDER__ 也可用。

标签: c windows unix networking cygwin


【解决方案1】:

我已经编写了自己的 htonll() 和 ntohll() 函数,它们可以在 uint64_t(64 位数字)的情况下解决 Cygwin 上的字节顺序问题。我认为它应该有效,但也希望您证明它确实是一个很好的解决方案。

我写了以下函数: 1. isBigEndian() 和 isLittleEndian() - 检查当前主机是使用大端还是小端 2.比我假设网络字节顺序是大端。因此,如果在当前主机上有 Little Endian,我将需要交换字节顺序,如果 Big Endian 比我只能使用在 htonll()/ntohll() 参数的编号中收到的字节序。 3. 我写了一个函数,可以分别将字节序从大或小到小或大交换为 64 位数字,即 swapEndianness()

所有代码如下:

bool isBigEndian() {
    int n = 1;
    // little endian if true
    if(*(char *)&n == 1) {
        return false;
    }
    return true;
}

bool isLittleEndian() {
    return  !(isBigEndian());
}

uint64_t swapEndianness(uint64_t num) {

    uint64_t b0, b1, b2, b3, b4, b5, b6, b7;
    uint64_t swapped_num;

    b0 = (num & 0x00000000000000ff) << 56u;
    b1 = (num & 0x000000000000ff00) << 40u;
    b2 = (num & 0x0000000000ff0000) << 24u;
    b3 = (num & 0x00000000ff000000) << 8u;
    b4 = (num & 0x000000ff00000000) >> 8u;
    b5 = (num & 0x0000ff0000000000) >> 24u;
    b6 = (num & 0x00ff000000000000) >> 40u;
    b7 = (num & 0xff00000000000000) >> 56u;

    swapped_num = b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7; 

    return swapped_num;
}

uint64_t htonll(uint64_t host_num64) {

    if(isLittleEndian()) {
        // swap little endian to big endian (network byte order)
        return swapEndianness(host_num64);
    }
    return host_num64;
}

uint64_t ntohll(uint64_t network_num64) {

    if(isLittleEndian()) {
        // swap big endian (network byte order) to little endian
        return swapEndianness(network_num64);
    }
    return network_num64;
} 

我还测试了上面的代码:

static void test_swap_endianness(void) {

    uint64_t number = 0x1123456789ABCDEF;
    printf("hex number = 0x%" PRIx64 "\n", number);

    uint64_t swappedNumber = swapEndianness(number);
    printf("hex swapped number: 0x%" PRIx64 "\n", swappedNumber);
}

并在交换 uint64_t 数字的字节顺序时获得正确的输出:

=========== test_swap_endianness ==============
hex number = 0x1123456789abcdef
hex swapped number: 0xefcdab8967452311

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 2023-03-26
    • 2013-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多