使用htons确定字节序

4

Consider the following code:

#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
    uint16_t num = 123;

    if (htons(num) == num) {
        printf("big endian\n");
    } else {
        printf("little endian\n");
    }
}

请问这段代码对检查字节序是否有效?我看到很多问题用各种指针/字符技巧来检查它,但我认为这更简单。它的原理是:如果将一个数字转换为网络字节序(大端序),如果它与原始数字相同,则表示您处于大端系统中。否则,您就处于小端系统中。

这个检查中是否存在假设错误?也许网络字节序并不总是大端序,虽然似乎已经标准化了


注意:我手头没有大端机器来检查这段代码,而模拟这样的系统的尝试正在变得不友好。 - Daniel Porteous
如果你想要完全彻底,这里的假设是字节顺序是大端或小端。曾经有一些架构使用了其他的字节顺序(例如,PDP-11将32位值0x01020304存储为0x02 0x01 0x04 0x03)。显然,只有两种可能性来存储16位值。 - Andy Schweig
实际问题是:为什么你要关心这个呢?htons及其相关函数的目的正是让用户不必关心字节序问题。在依赖特定字节序的托管环境中编写的代码通常会因设计缺陷而失效。 - too honest for this site
这是一道来自《Unix环境高级编程》的练习题,要求编写代码来确定字节序。我的答案是这段代码,而他们则使用了常规的位测试方法。我只是想确认一下我的答案是否正确。 - Daniel Porteous
@DanielPorteous - 如果您想要访问其中一个,请发送您的authorized_keys文件至noloader,gmail账户。我保留了一台旧的PowerMac与PowerPC在线测试使用。 - jww
2个回答

7

这足以在运行时检查字节序。

在大端系统上,htons(以及ntohshtonlntohl)被定义为无操作,而在小端系统上,它们执行字节交换。

编辑:

这也可以使用联合来实现。下面的检查检测大端和小端,以及其他更奇特的字节序。

#include <stdio.h>
#include <stdint.h>

union echeck {
    uint32_t i;
    char c[4];
} echeck = { .c = { 0x01, 0x02, 0x03, 0x04 } };

int main()
{
    if (echeck.i == 0x01020304) {
        printf("big endian\n");
    } else if (echeck.i == 0x04030201) {
        printf("little endian\n");
    } else if (echeck.i == 0x02010403) {
        printf("pdp endian\n");
    } else {
        printf("other endian\n");
    }
    return 0;
}

太棒了,我不知道那些函数在大端系统上是无操作的,这很有趣。谢谢! - Daniel Porteous
你是真的想说 php-endian 吗?也许是 pdp-endian? - R.. GitHub STOP HELPING ICE
@R.. 是的,那是个打字错误。已经修复了。 - dbush

2
原则上,C语言允许 uint16_t 的表示中的位按照任何实现定义的顺序排列,而不仅仅是“小端”或“大端”。如所述,您的测试只告诉您 htons 单独置换了位0、1、3、4、5、6和2、7-15,而没有混合它们。
如果您迭代所有2的幂,并发现对于0..15中的ihtons(1<<i)==1<<i,那么您可以得出结论,顺序肯定是大端。如果您发现对于0..15中的ihtons(1<<i)==1<<(i^8),那么您可以得出结论,顺序是小端。否则,您就有一个非常不寻常的表示。
事实上,奇怪的事情不会发生,您的测试应该足够了。

是的,这正是我所预料的复杂性,但正如你所指出的那样,在任何合理的系统中,我都不认为这会成为一个问题。非常好的答案,谢谢。 - Daniel Porteous

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接