【问题标题】:How does the computer distinguish a number and a character?计算机如何区分数字和字符?
【发布时间】:2018-10-07 15:24:14
【问题描述】:

根据 ASCII 表,当我们将 'TAB' 和十进制 9 存储到内存中时,它们都存储为“1001”。计算机如何知道它是“TAB”还是十进制 9?

【问题讨论】:

    标签: memory operating-system


    【解决方案1】:

    文本数据或任何其他类型的数据本身没有区别,因此计算机无法区分 ASCII 字符或内存中的普通数字。

    然而,作用于该数据的进程会以不同的方式处理不同的内存内容,并带有烘焙到其指令序列中的数据类型的“知识”。例如,对printf() 的调用要求参数是string of characters(以空字符结尾的字符串)。所以你有它,知识在过程中,而不是数据。

    这可能会导致问题,因为由人类程序员确保将正确类型的参数(数据)传递给特定的函数(进程)。 - 幸运的是,编译器(和其他在开发过程中使用 compile time 或之前使用的帮助器,例如使用 static analysis)也“知道”如何键入内容(在 strongly typed languages 的情况下),因此程序错误通常不会编译。 - 但在任何情况下,例如在 C 中,您都可以将任何内存内容视为您想要的任何类型的数据(例如,type casting),即使是可执行代码也有一些限制。

    在运行时,(几乎)没有什么可以阻止程序将任意内存位置的数据解释为 ASCII 文本或纯数字,这只是表示的问题。

    但是,对于程序的结构以及将文本存储在何处,存在一些约定,即编译时已知的静态字符串,即纯文本。通常,它们被放置在程序的.data or .rodata segment 中(通常不在 .text 段中)。您可以像这样使用strings 扫描二进制程序:

    $ strings /usr/bin/strings
    

    或者,如果您想了解更多关于 .data / .rodata 段的信息,binutils 的objdump 可能会派上用场:

    $ objdump -h /usr/bin/strings
    $ objdump --full-contents --section .rodata /usr/bin/strings
    

    使用十六进制编辑器也可以做到这一点:

    $ xxd <my-binary>
    $ xxd /usr/bin/strings
    

    最后,由单个程序知道如何处理其内存,以及如何解释其中的二进制数据的各个位。该程序通常在操作系统内部运行,该操作系统定义了对哪些内存区域可访问以及如何访问的其他类型的限制,并且该程序可能正在与盒子外部或内部的其他进程对话(访问权限,需要访问权限的系统 API某些类型的数据,例如文本或二进制数据)。但同样,在这种情况下,知识也存在于过程中,而不是数据本身。硬件(即处理器和内存(RAM、FLASH...))不会从根本上区别对待文本数据与其他类型的数据。

    【讨论】:

      【解决方案2】:

      让我以古老的 VAX 为例。假设您在某个位置定义了 8 个字节的内存:

      location:
           .ASCII /ABCDEFGH/
      

      说明

       MOVC3   location, 8, some_other_location
      

      将内存视为字符。

      说明

      ADDL2 location, R0
      

      将相同的内存视为整数值

      说明

      MULD2 location, R8
      

      将相同的内存视为浮点值。

      指令:

      jmp location
      

      将内存视为代码(但可能会呕吐)。

      记忆就是记忆。如何解释它取决于在内存上操作的指令。计算机不知道某个位置存储了什么。这由程序员来决定。

      【讨论】:

        【解决方案3】:

        计算机不“知道”内存中的特定地址是什么类型,这些知识已融入程序的指令中。

        当您编写程序并看到您的变量时,编译器会创建汇编代码,将那段数据写入某处,并且在其他地方有一些其他代码读取内存地址并将其解释为字符 /em>。它一个字符的知识没有存储在内存中。该内存地址的位置是将这两个操作联系在一起的唯一因素。

        当读取该位置时,程序集不会说“查看那里的数据类型”,它只是说“加载此内存位置并将其视为 char”。例如,如果某些东西用 char 以外的东西覆盖了该内存地址,CPU 无论如何都会将该内存作为 char 加载,结果可能会发生各种奇怪的事情。

        例如,在以下程序中:

        #include <stdio.h>
        
        int main()
        {
            int x; 
            x = 9;
            char* y;
            y = &x;
            printf("\"%s\" \"%d\"\n", y, x);
            printf("%p\n%p", y, &x);
            return 0;
        }
        

        你会得到如下输出:

        "       " "9"                                                                                                                                                                                                                                    
        0x7ffd401ce68c                                                                                                                                                                                                                                   
        0x7ffd401ce68c
        

        所以我们看到内存中的 same 位置被视为 char 和 int。内存中的值不知道也不关心它被用作什么。

        【讨论】:

        • 你的意思是有留给字符的地方吗?存储在该位置的任何内容都将被视为字符。其他变量类型将类似。谢谢~
        • 不,我的意思是内存不知道或不关心每个位置存储的类型,您的程序是唯一会“知道”某个位置的内存应该被处理的地方某种方式。
        • 所以在这种情况下,CPU 读取并返回它在给定地址找到的数据,直到找到空值,C 编译器将其解释为 8 位字符,产生 ASCII 字符 9 (水平选项卡)。那是对的吗?然而,一个典型的 C 整数在内存中占用 32 位(在 little-endian 系统上表示为 0x01000009?)。如果 CPU 确实读取此信息直到 null 并且 C 将其解释为字符,为什么输出不是四个字符?我显然错了,但在哪里?
        • 我想我知道我错在哪里了。整数 9 在 C 中内存中的表示为 0x09000000。我将您的代码更改为包含printf("\"%c%c%c%c\" \"%d\"\n", *y, *(y+1), *(y+2), *(y+3), x); 以找出答案。我不确定为什么会这样,但可以等待:)
        猜你喜欢
        • 2017-12-19
        • 1970-01-01
        • 2020-12-11
        • 2017-01-26
        • 2015-05-03
        • 1970-01-01
        • 1970-01-01
        • 2013-07-17
        相关资源
        最近更新 更多