理解字节序 - 变量值

3

我正在使用一段代码(在本网站的其他地方找到)来在运行时检查字节序。

static bool isLittleEndian()
{
  short int number = 0x1;
  char *numPtr = (char*)&number;

  std::cout << numPtr << std::endl;
  std::cout << *numPtr << std::endl;

  return (numPtr[0] == 1);
}

在调试模式下,numPtr的值如下:0x7fffffffe6ee "\001" 我认为十六进制的第一部分是指针的内存地址,第二部分是它所持有的值。我知道在旧式C++中\0代表空终止符,但为什么它在前面呢?这与字节序有关吗?
在小端机器上:01是第一个字节,因此是最不重要的字节(字节位置0),\0是第二个字节/最后一个字节(字节位置1)。
另外,cout语句不打印指针地址或其值。原因是什么?

你在使用numPtr之后才定义它,这样怎么可能编译通过呢? - Some programmer dude
现在已经被更改了。是我自己复制和粘贴错误。 - nf313743
为什么需要在运行时检查字节序?这不是每个端口的make文件的一部分吗? - Bo Persson
7个回答

2
其他人已经清楚地回答了"\000"的含义,所以这是对您问题的回答:
在小端机器上:01是第一个字节,因此是最不重要的(字节位置0),而\0是第二个字节/最终字节(字节位置1)。
是的,这是正确的。如果您查看像0x1234之类的值,则由两个字节组成,高部分为0x12,低部分为0x34。术语“小端”意味着低部分先存储在内存中。
addr:   0x34
addr+1: 0x12

你知道“endian”这个术语在计算机行业出现之前就已经存在了吗?它最初是由乔纳森·斯威夫特在他的书《格列佛游记》中使用的,用来描述人们是否从蛋的尖端或者圆端吃。


1

检查字节序最简单的方法是让系统自己完成:

if (htonl(0xFFFF0000)==0xFFFF0000) printf("Big endian");
else printf("Little endian");

1

这不是一个后面跟着“01”的\0,而是单个字符\001,它代表八进制数1。这是你字符串中唯一的字节。它后面还有另一个值为零的字节,但由于它被视为字符串终止符,所以你看不到它。


1
首先,这种类型的函数是完全没有用处的:在一个 sizeof(int) 为4的机器上,有24种可能的字节顺序。当然,大多数都没有意义,但我至少见过三种。而字节序不是唯一影响整数表示的因素。如果你有一个 int,并且想要获取低位8位,请使用 intValue & 0xFF,对于接下来的8位,使用 (intValue >> 8) & 0xFF
关于您的具体问题:我认为您所描述的“看起来像这样”是在调试器中断点处看到的。在这种情况下,numPtr 是一个 char*(一个 unsigned char const* 更合理),因此调试器假定它是一个 C 风格的字符串。而 0x7fffffffe6ee 是地址;其后面的内容是编译器认为是 C 风格字符串的内容,编译器将其显示为字符串,即 "..."。假设您的平台是传统的小端(Intel);指向 C 风格字符串的指针看到的是数字值序列 1, 0。当然,0 相当于 '\0',因此它被视为一个字符的字符串,该字符的编码为 1。没有任何可打印的字符的编码为 1,也不对应任何正常的转义序列(例如 '\n''\t' 等)。因此,调试器使用八进制转义序列输出它,即 '\' 后跟 1 到 3 个八进制数字。(传统的 '\0' 只是这种情况的特例;一个 '\' 后跟一个八进制数字。)它输出 3 个数字,因为(可能)它不想向前查看以确保下一个字符不是八进制数字。(例如,如果序列是两个字节的 1, 49,那么 49 是通常编码中的 '1',如果它只输出一个字节作为 1 的八进制编码,结果将是 "\11",这是一个单字符字符串——在通常的编码中对应于 '\t'。)所以您得到了 " 这是一个字符串,\001 第一个字符的编码为 1(没有可显示的表示)," 这是字符串的结尾。


你见过的第三种字节序是什么,大端、小端和...? - edA-qa mort-ora-y
@edA-qamort-ora-y 1234、4321和3412。最后一个是在Intel 8086上的MS-DOS下使用Microsoft C编译的。当然,今天仍然有一些机器(由Unisys销售)的sizeof(int)为6,表示为有符号数,且int中有8个保留位必须为0。 - James Kanze

0
你看到的"\001"只是一个字节。它可能是八进制表示法,需要三个数字才能正确表示0到255的(十进制)值。

0

\0 不是 NUL,调试器将 numPtr 显示为字符串,其第一个字符为 ASCII 中的 \001 或控制-A。第二个字符是 \000,因为在显示字符串时不显示 NUL。在大端机器上,“number”的两个字符字符串版本将显示为“\000\001”,而不是在小端机器上显示的“\001\000”。


0
此外,cout语句不打印指针地址或其值。原因是什么?
因为在打印时,char和char指针与整数的处理方式不同。
当您打印一个char时,它会从正在使用的字符集中打印字符。通常,这是ASCII或某个ASCII的超集。在ASCII中,值0x1是不可打印的。
当您打印char指针时,它不会打印地址,而是将其作为以null结尾的字符串打印出来。
要获得所需的结果,请将char指针转换为void指针,并将char转换为int。
std::cout << (void*)numPtr << std::endl;
std::cout << (int)*numPtr << std::endl;

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