【发布时间】:2018-10-07 15:24:14
【问题描述】:
根据 ASCII 表,当我们将 'TAB' 和十进制 9 存储到内存中时,它们都存储为“1001”。计算机如何知道它是“TAB”还是十进制 9?
【问题讨论】:
根据 ASCII 表,当我们将 'TAB' 和十进制 9 存储到内存中时,它们都存储为“1001”。计算机如何知道它是“TAB”还是十进制 9?
【问题讨论】:
文本数据或任何其他类型的数据本身没有区别,因此计算机无法区分 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...))不会从根本上区别对待文本数据与其他类型的数据。
【讨论】:
让我以古老的 VAX 为例。假设您在某个位置定义了 8 个字节的内存:
location:
.ASCII /ABCDEFGH/
说明
MOVC3 location, 8, some_other_location
将内存视为字符。
说明
ADDL2 location, R0
将相同的内存视为整数值
说明
MULD2 location, R8
将相同的内存视为浮点值。
指令:
jmp location
将内存视为代码(但可能会呕吐)。
记忆就是记忆。如何解释它取决于在内存上操作的指令。计算机不知道某个位置存储了什么。这由程序员来决定。
【讨论】:
计算机不“知道”内存中的特定地址是什么类型,这些知识已融入程序的指令中。
当您编写程序并看到您的变量时,编译器会创建汇编代码,将那段数据写入某处,并且在其他地方有一些其他代码读取内存地址并将其解释为字符 /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。内存中的值不知道也不关心它被用作什么。
【讨论】:
printf("\"%c%c%c%c\" \"%d\"\n", *y, *(y+1), *(y+2), *(y+3), x); 以找出答案。我不确定为什么会这样,但可以等待:)