ASCII字符串和字节序

Cha*_*via 39 c ascii endianness

和我一起工作的实习生向我展示了他在计算机科学方面考试的关于字节序问题的考试.有一个问题显示ASCII字符串"My-Pizza",学生必须显示该字符串将如何在小端计算机的内存中表示.当然,这听起来像一个技巧问题,因为ASCII字符串不受端序问题的影响.

但令人震惊的是,实习生声称他的教授坚持认为该字符串将表示为:

P-yM azzi
Run Code Online (Sandbox Code Playgroud)

我知道这不可能是正确的.在任何机器上都不能像ASCII字符串那样表示ASCII字符串.但显然,教授坚持这样做.所以,我写了一个小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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这清楚地表明字符串在内存中存储为"My-Pizza".一天后,实习生回到我身边,告诉我教授现在声称C正在自动转换地址,以正确的顺序显示字符串.

我告诉他他的教授很疯狂,这显然是错的.但是为了检查我自己的理智,我决定在stackoverflow上发布这个,所以我可以让其他人确认我在说什么.

所以,我问:谁在这里?

Hea*_*utt 28

毫无疑问,你是对的.

ANSI C标准6.1.4指定通过"连接"文字中的字符将字符串文字存储在内存中.

ANSI标准6.3.6还指定了添加对指针值的影响:

当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型.如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向偏离原始元素的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式.

如果归因于这个人的想法是正确的,那么当整数用作数组索引时,编译器也必须使用整数数学.许多其他谬误也会产生想象力.

该人可能会混淆,因为(不同于一个字符串初始化),多字节chacter常量如"ABCD" 存储在endian顺序.

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

  • 可能是教授正在调试器中以32位模式查看内存并且被字节序混淆了? (11认同)
  • 这里的每个人都知道,查看顺序字节数据作为小端机器上的字将显示交换字节 - 这实际上是小端的定义.OP所涉及的声明是由他的教授提出的,不是在调试器中查看转储.至少,OP收到的信息是关于内存中字节的实际顺序.手臂椅心理学家试图进入教授的脑海,批评没有的正确答案,这是相当恼人的.我认为这些人是权威人物的奴隶. (3认同)

AnT*_*AnT 16

教授很困惑.为了看到像'P-yM azzi'这样的东西你需要采用一些内存检查工具,以'4字节整数'模式显示内存,同时为你提供高阶中每个整数的"字符解释"字节到低位字节模式.

当然,这与字符串本身无关.并且说字符串本身在小端机器上表示是完全无稽之谈.

  • 嗯......也许,但在这种情况下,"正确"的答案是什么?如果将小端存储器视为一个字节序列,那么就会看到"My-Pizza".如果将其解释为2字节整数的序列,那么它将是'yM P-zi az'.在4字节整数的情况下,它是'P-yM azzi'.最后一个8字节的int解释会给'azziP-yM'.所有这些"解释"就是 - 解释,在内存中显示*数据的方法.一旦人们明白他们来自哪里,所有这些都是"正确的".没有什么能给教授提供*坚持*只是其中一个作为"正确"的基础. (6认同)
  • 调试器说"这个整数,如果存储在具有不同字节序的机器上,将在内存中表示这个不同的字符串",这没什么意义. (2认同)

Dmi*_*ant 10

如果我们谈论的是每个字符使用8位的系统,那么教授就错了.

我经常使用实际使用16位字符的嵌入式系统,每个字都是little-endian.在这样的系统上,字符串"My-Pizza"确实将被存储为"yMP-ziaz".

但只要它是一个每字符8位的系统,该字符串将始终存储为"My-Pizza",独立于更高级别架构的字节序.

  • 我研究过的一款产品使用的是Texas Instruments DSP(我认为是2808),其最小的可寻址存储单元是16位. (2认同)
  • @ s1lence实际上,就C标准而言,字节不一定是8位宽。C99草案标准第3.6节将字节定义为:**数据存储的可寻址单元,其大小足以容纳执行环境的基本字符集的任何成员**,并且其宽度(以位为单位)存储在常量CHAR_BIT中,该常量必须*大于或等于*8。因此,如果该DSP的最小可寻址存储单元为16位字,则该系统上的字节*为* 16位宽。 (2认同)

caf*_*caf 9

你可以很容易地证明编译器没有进行这种"神奇"的转换,通过在一个不知道它传递了字符串的函数中进行打印:

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);
}
Run Code Online (Sandbox Code Playgroud)

地狱,你甚至可以编译成汇编gcc -S并最终确定没有魔法.

  • ASM为+1.此外,您可以编写此例程IN程序集来证明它. (6认同)

小智 9

Endianness定义多字节值中的字节顺序.字符串是单字节值的数组.因此,每个值(字符串中的字符)在little-endian和big-endian体系结构上都是相同的,并且endianness不会影响结构中值的顺序.