ASCIIstring和字节序

一位和我一起工作的实习生向我展示了他在计算机科学方面所进行的关于sorting问题的考试。 有一个问题,显示一个ASCIIstring“我的比萨”,学生必须显示如何将该string将在一个小端计算机上的内存中表示。 当然,这听起来像个诡计的问题,因为ASCIIstring不受endian问题的影响。

但令人震惊的是,实习生声称他的教授坚持认为这个string可以表示为:

P-yM azzi 

我知道这是不对的。 在任何机器上,ASCIIstring都不会像这样表示。 但显然,教授坚持这一点。 于是,我写了一个小C程序,并告诉实习生把它交给他的教授。

 #include <string.h> #include <stdio.h> int main() { const char* s = "My-Pizza"; size_t length = strlen(s); for (const char* it = s; it < s + length; ++it) { printf("%p : %c\n", it, *it); } } 

这清楚地表明该string在内存中被存储为“我的比萨”。 一天后,实习生回到我身边告诉我,教授现在声称C正在自动转换地址,以正确的顺序显示string。

我告诉他他的教授疯了,这显然是错的。 但是为了检查我自己的理智,我决定把它发布到stackoverflow上,以便让其他人确认我在说什么。

所以,我问:谁在这里?

毫无疑问,你是对的。

ANSI C标准6.1.4规定string文字通过“连接”文字中的字符存储在内存中。

ANSI标准6.3.6还指定了对指针值的添加效果:

当具有整数types的expression式被添加到指针或从指针中减去时,结果具有指针操作数的types。 如果指针操作数指向数组对象的一个​​元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果数组元素和原始数组元素的下标之差等于整数expression式。

如果归因于这个人的想法是正确的,那么当整数被用作数组索引时,编译器也将不得不用整数运算。 许多其他的谬论也会导致想象力的落空。

这个人可能会感到困惑,因为(不像一个string初始值设定项),像ABCD这样的多字节字符常量是以字节顺序存储的。

一个人可能会为此感到困惑的原因很多。 正如其他人在这里所build议的那样,他可能会误读他在debugging器窗口中看到的内容已被字节交换以便读取int值的内容。

教授很困惑。 为了看到像“P-YM azzi”这样的东西,你需要采用一些内存检查工具,以“4字节整数”模式显示内存,同时给你一个“更高级的每个整数的字符解释”字节到低阶字节模式。

当然,这与string本身无关。 而且要说这个string本身在小端机器上的performance完全是无稽之谈。

如果我们谈论一个使用每个字符8位的系统,教授是错误的。

我经常使用实际使用16位字符的embedded式系统,每个字都是小端。 在这样的系统中,string“我的比萨”确实被存储为“yMP-ziaz”。

但是只要是每字符8位的string,string将总是作为“我的比萨”存储,而不依赖于更高级架构的字节顺序。

你可以很容易地certificate编译器没有做这样的“魔术”转换,通过在不知道已经传递string的函数中进行打印:

 int foo(const void *mem, int n) { const char *cptr, *end; for (cptr = mem, end = cptr + n; cptr < end; cptr++) printf("%p : %c\n", cptr, *cptr); } int main() { const char* s = "My-Pizza"; foo(s, strlen(s)); foo(s + 1, strlen(s) - 1); } 

地狱,你甚至可以编译汇编到gcc -S并确定地确定没有魔法。

字节顺序定义了多字节值内的字节顺序。 string是单字节值的数组。 因此,每个值(string中的字符)在小端和大端架构上都是相同的,并且字节序不会影响结构中的值的顺序。

但令人震惊的是,实习生声称他的教授坚持认为这个string可以表示为:

P-YM azzi

它将被表示为,代表什么? 用户表示为32位整数转储? 或者在P-yM azzi中代表/布置在计算机内存中?

如果教授说“我的比萨”会在计算机内存中被表示为“P-yM azzi”,因为计算机是小端架构的,那么请教某位教授如何使用debugging器! 我认为这是所有教授混淆的地方,我有一个暗示,教授不是一个编码员(不是我瞧不起教授),我想他没有办法用代码来certificate他了解了endian-ness。

也许这位教授大概在一个星期前就学会了端到端的东西,然后他错误地使用了一个debugging器,很快就对他在计算机上的独特见解感到高兴,然后马上传给他的学生。

如果说教授说机器的sorting对于记忆中的string是如何表示的话,他需要清理自己的行为,有人应该纠正自己的行为。

如果教授举了一个例子,而不是根据机器的排列顺序来表示整数是如何在机器上performance/布置的,那么他的学生就可以明白他在教什么。

我假设教授试图用endian / NUXI问题来比喻一下,但是当你把它应用到实际的string时你是对的。 不要让这个事情脱离他试图教给学生一个观点,以某种方式思考问题的事实。

你可能会感兴趣,有可能在一个big-endian机器上模拟一个little-endian的架构,反之亦然。 编译器必须发出代码,只要引用它们,它就会自动地用char*指针的最低有效位来混淆:在一个32位的机器上,你会映射00 < – > 11和01 < – > 10。

所以,如果你在一个big-endian的机器上写入数字0x01020304 ,并且用这个地址重新读回这个字节的第一个字节,那么你得到最低有效字节0x04 。 C的实现是小端的,即使硬件是大端的。

你需要一个类似的伎俩短期访问。 未alignment的访问(如果支持的话)可能不会引用相邻的字节。 您也不能使用大于一个单词的types的本地存储,因为一次读回一个字节时,它们会出现字词交换。

显然,little-endian机器不会一直这样做,这是一个非常专业的要求,它阻止你使用本地的ABI。 听起来好像教授认为实际数字是“实际上”的大端,而对于小端架构真正是什么和/

确实,string在32位计算机上被表示为“ P-yM azzi ”,但是只有通过“表示”您的意思是“按照增加地址的顺序读取表示的字,但是打印每个字的字节大 -尾数”。 正如其他人所说,这是一些debugging器内存视图可能做的,所以它确实内存内容的表示。 但是,如果要表示单个字节,则更常用的方式是按地址增加的顺序列出它们,而不pipe字是存储为是或是否,而不是将每个字表示为多字符字面值。 当然,没有指针摆弄,如果教授的select使他觉得有一些,那就误导了他。

另外,(我很久没有玩这个了,所以我可能是错的)他可能会想到pascol,那里的string被表示为“打包数组”,其中,IIRC是字符打包成4个字节的整数?

AFAIK,sorting只有当你想把一个大的值分解成小的时候才有意义。 所以我不认为C风格的string会受到影响。 因为他们毕竟只是字符数组。 当你只读一个字节时,如果你从左边或右边读取它,怎么会影响?

很难读懂教授的思想,当然编译器除了在BE和LE系统上将字节存储到相邻的增长地址之外,其他任何事情都没有做任何其他的事情,但是,以字大小的数字显示内存正常的,无论字大小是多less,我们写成1000个。 不是000,1。

 $ cat > /tmp/pizza My-Pizza^D $ od -X /tmp/pizza 0000000 502d794d 617a7a69 0000010 $ 

为了logging,y == 79,M == 4d。

我遇到了这个,觉得有必要清除它。 这里没有人似乎已经解决了byteword的概念,或者如何解决它们。 一个字节是8位。 一个字是字节的集合。

如果电脑是:

  • 字节可寻址
  • 与4字节(32位)字
  • 单词alignment
  • 内存是“物理”查看(不转储和字节交换)

那么确实教授会是对的。 他没有说明这一点,certificate他并不完全知道他在说什么,但是他理解了这个基本概念。

字节内的字节顺序:(a)Big Endian,(b)Little Endian

字节内的字节顺序:(a)Big Endian,(b)Little Endian

字符和整数数据的话:(a)大端,(b)小端

字符和整数数据的话:(a)大端,(b)小端

参考

  • 英特尔®Fortran编译器XE 13.0用户和参考指南

教授的“C”代码看起来像这样吗? 如果是这样,他需要更新他的编译器。

 main() { extrn putchar; putchar('Hell'); putchar('o, W'); putchar('orld'); putchar('!*n'); }