计算机如何确定字节的数据类型?


31

例如,如果计算机已10111100存储在RAM的特定字节中,计算机如何知道将此字节解释为整数,ASCII字符或其他内容?类型数据是否存储在相邻字节中?(我认为情况并非如此,因为这将导致一个字节使用两倍的空间。)

我怀疑也许计算机甚至不知道数据类型,只有使用它的程序才知道。我的猜测是,由于RAM是R AM,因此不能按顺序读取,因此某个特定程序只是告诉CPU从特定地址获取信息,而该程序定义了如何处理它。这似乎适合编程,例如需要类型转换。

我在正确的轨道上吗?


4
附带说明:如果要讨论类型,则必须在语言环境中进行。留给编译器来处理这类事情(符号,检查类型,操作,类型转换,地址ram等)。CPU和RAM仅知道字节
jean

4
字节的数据类型是一个字节。除此之外,计算机什么都不知道。程序可以将一个字节或一组字节解释为一种特定的数据类型,并尝试对它们进行操作,但是那里没有限制。同一字节组可以解释为一种以上的数据类型(即,将指针转换为值类型,类似C的并集等)。没有顺序读取RAM并不重要。-这更多是因为RAM是通用的。-例如,寄存器也不是顺序读取的,而是键入的。
BrainSlugs83

5
对我自己来说,这是无耻的插件,但是这个问题基本上是在一个月前的程序员SE上提出的。 这是我的回答。在这一点上它有点长,但是从几个不同的角度来攻击它。
沙兹(Shaz)2015年

2
硬件与数据类型无关的事实的一个有用的结果是,单个字节(或字等)可由程序以多种方式解释。值得注意的是,暂时将浮点数解释为整数可用于计算快速反平方根
Aoeuid 2015年

@ BrainSlugs83,您可以考虑将其转换为答案吗?
DW

Answers:


38

您的怀疑是正确的。CPU不在乎数据的语义。但是,有时确实会有所作为。例如,当参数被语义签名或未签名时,某些算术运算会产生不同的结果。在这种情况下,您需要告诉CPU您打算使用哪种解释。

程序员应了解自己的数据。CPU仅服从命令,而没有意识到命令的含义或目标。


1
关于“何时对参数进行语义签名或无符号签名”,CPU将如何知道?CPU操作仅看到参数字节,而缺乏那种数据类型上下文感知。您可以通过选择适当的CPU操作(或编译器执行)来隐含数据类型。
希夫

4
@Shiv在这种情况下,实际上向CPU发出了一条不同的指令来处理带符号的数字与无符号的数字。如OP所怀疑的那样,该程序不得不提供这些详细信息,因为CPU不知道。
Cort Ammon-恢复莫妮卡2015年

2
只要我记得自己,就一直在使用计算机,即使我知道CPU并不关心我们在高级编程中使用的高级构造,但是这种概念上的分离仍然让我时不时地感到困惑。
Loupax 2015年

1
@Loupax好吧,使用一个非常低级的程序集可以提供很多帮助-即使mov al, 42是高级的-显然只有一个可能的指令可以调用,但是它仍然有些抽象。但是,mov.8 al, 42显式使用使这一点变得很痛苦:)
Luaan 2015年

1
@Shiv:我想指出,有些机器在内存中键入数据。这些被称为标记内存体系结构(或简称为标记体系结构),但是它们在商业上还没有常规体系结构成功,部分原因是因为我们现在主要使用编译语言(而不是汇编语言)进行编程,并且编译器负责键入。参见:en.wikipedia.org/wiki/Tagged_architecture
slebetman 2015年

14

正如其他人已经回答的那样,当今的通用CPU不知道给定的内存位置包含什么。软件决定。

但是,还有其他可能性。例如,Lisp Machines使用标记的体系结构来存储每个存储位置的类型。这样,硬件本身就可以完成一些高级语言的工作。

甚至现在,我猜您仍可以考虑将Intel,AMD,ARM和其他体系结构中的NX位遵循相同的原理:在硬件级别区分给定的存储区是否包含数据或指令。

同样,仅出于完整性考虑,在哈佛体系结构(如某些微控制器)中,数据和指令在物理上是分开的,因此CPU确实对正在读取的内容有所了解。

在这个Quora问题中,有一些关于标记的内存如何工作,其性能影响和消亡等方面的评论。


标记的体系结构是一个有趣的笔记。会快很多吗?
暗杀手

4

是。该程序只是从内存中获取一个字节,并且可以根据需要对其进行解释。


3

没有类型注释。
RAM存储纯数据,然后程序定义要做什么。

使用CPU寄存器要困难一些,如果您具有给定类型的寄存器(例如FPU),则可以告诉其中的内容。
浮点寄存器上的操作明确地使用类型化数据。您或您的编译器会告诉您应在何时何地放置什么内容,因此您没有这种自由。
计算机对RAM中的基础数据不做任何假设,在寄存器中也没有任何例外-一个例外-CPU中的类型寄存器是已知类型的,可以对其进行优化。这只是为了表明在某些地方数据是预期类型的​​,但是没有什么可以阻止您将字符串转换为浮点数并将它们相乘。

在编程语言中,您可以指定类型,在高级语言中,数据是通用的,而编译器/解释器/ VM会对内部内容进行编码,而会产生额外的开销。
例如,在C语言中,您的指针类型告诉您如何处理数据,如何访问数据。

当然,您可以读取字符串(字符),然后将其视为浮点值,整数并将其混合。


FPU寄存器中的偶数位也不总是代表浮点值。在过去(也许不再那么多了吗?),一种常见的优化方法是使用浮点寄存器(64位或更大)来复制数据,其速度要比通用/整数寄存器(32位)大一倍,他们通常能够以两倍的速度复制数据。
赛斯2015年

1
我完全同意您的意见,这就是为什么我写某人可能会在那儿推弦乐的原因。同时人们对整数进行浮点运算,因为它更快。这就是我想说的!
Evil

@HCBPshenanigans提供了操作浮点值的指令。如果使用FADD,则只有(4,8或10)字节的内存组保留浮点数才有意义。对于几种指令来说都是这样:将两个整数相乘仅在它们是整数时才有意义,而跳转仅在它是地址时才有意义。
JDługosz

@seth和evilJS不是旧式浮点堆栈8087指令的情况,而是新的CIMD寄存器的情况,它们可能仅用于装载/保存而没有解释(尽管它们必须对齐),并且需要注意如果从未使用过CIMD寄存器,则无需将其保存在上下文切换中。如果(仅)通过XMM寄存器移动8个字节,则将导致净亏损,因为需要保存整个集合。
JDługosz

3

CPU不在乎,它执行汇编代码,该代码只是移动数据,对其进行移位,相加或相乘...

数据类型是一种高级语言概念:在C或C ++中,您需要为要处理的每条数据指定类型。C / C ++编译器负责将这些数据片段转换为供CPU处理的正确命令(编译器编写汇编代码)

在某些甚至更高级别的语言中,可以推断出类型:例如,在Python或Javascript中,不必指定数据类型,但是数据具有类型,您不能添加带有整数的字符串,但是可以添加一个带有整数的浮点数:“编译器”(对于Javascript,它是JIT(Just in Time)编译器。Javascript通常称为“解释性”语言,因为历史上浏览器会解释Javascript代码,但如今Javascript引擎是编译器。

代码总是最终会被编译成机器代码,但是显然机器代码格式取决于您所针对的机器(例如,x86 64位代码在x86 32位机器或ARM处理器上无法使用)

因此,实际上,运行解释代码涉及很多层。

Java和C#是其他有趣的代码,因为Java或C#代码在技术上被“编译”为Java二进制(字节码),但是该代码本身随后由Java运行时解释,该运行时特定于基础硬件(需要安装一个针对正确的机器以运行Java二进制文件(JAR)的JRE)


不论是否为JIT,编译器都可以编译。解释器无需编译即可解释(因为如果不是编译器!)。他们是完全不同的东西。对于由于字节码解释而造成的“ Java有趣”,请考虑甚至x86机器代码实际上也将被微处理器直接解释(甚至编译为)微码
hmijail

感谢您的澄清...同意:编译器进行编译,解释器进行解释。对于Javascript来说,故事有些复杂,因为一些较旧的浏览器会解释代码,而更现代的浏览器实际上是即时编译的,这也许就是为什么即使它仍然被称为“解释”语言的原因从技术上讲不再。
MrE

但是AFAIK,JS开始解释,然后可能根据需要进行编译。而且,JIT可以根据很多情况从解释转换为编译再转换为解释。例如,可能为具有给定类型的变量编译了一段代码。但是随后使用具有不同类型的变量再次运行代码,因此无法使用现有的已编译代码,因此解释器会跳入-直到再次为新类型编译代码...
hmijail

您引用了我没有说的话,请删除它,因为那是完全错误的。微码与操作系统无关。这是微处理器内部的东西。32位或64位也与此无关。
hmijail

3

数据类型不是硬件功能。CPU知道几个(很多)不同的命令。这些被称为CPU 的指令集

x86指令集是最著名的指令集之一。如果在此页面上搜索“乘”,您将获得50个结果。MULPDMULSD双打的乘法, FIMUL整数乘法,...

这些命令在寄存器上起作用。寄存器是内存插槽,无论这些位代表什么,它们都可以包含固定数量的位(通常为32或64,具体取决于CPU使用的体系结构)。因此,CPU指令以不同的方式解释寄存器的值,但是值本身没有类型。

Stuart WilliamsPyCon 2017上给出了一个示例:

在此处输入图片说明


1
请注意,这并非完全正确:有些专用寄存器不能包含任意值(例如,指针寄存器不仅是任何地址,而且不允许任意加法,或者是浮点寄存器,您可以在其中使用任意值)不会存储非规范化值)。但是您的答案对大多数架构上的通用寄存器都是正确的。
吉尔(Gilles)'所以

2

...一个特定的程序只是告诉CPU从一个特定的地址中获取信息,然后该程序定义了如何处理它。

究竟。但是RAM不会“顺序”读取,它代表随机存取存储器,而正好相反。

除了知道字节什么之外,您甚至都不知道它是字节还是更大项目(例如浮点数)的片段。

我想通过举一些具体的例子来补充其他答案。

考虑一下01000001。该程序可能会将其作为大量数据的一部分从一个位置复制到另一位置,而不考虑其含义。但是将其复制到文本模式视频缓冲区使用的地址将导致该字母A显示在屏幕上的某些位置。当卡处于CGA图形模式时,完全相同的操作将显示红色像素和蓝色像素。

在寄存器中,它可以是65的整数。进行算术运算以设置32位可能意味着没有上下文的任何含义,但可能具体是将字母更改为小写。

8086 CPU(仍)具有称为DAA ※的特殊指令,该指令在寄存器包含两位十进制数字时使用,因此,如果您仅使用该指令,则会将其解释为两位数字41

程序崩溃是因为读取了一个存储字,认为它是一个指针,而在其他地方存储了一个东西。

使用调试器检查内存,使用映射来指导显示解释。没有此符号信息,低级调试器就可以指定:以16位字显示此地址,以长浮点数,字符串等形式显示此地址。查看网络数据包转储或未知文件格式,将其弄乱是一个挑战。

这是现代计算机体系结构中强大功能和灵活性的主要来源:存储单元可以表示任何内容,数据或指令,这些内容,内容或指令仅隐含在它对程序“意味着”的意义上,即它对值的作用以及对后续操作的影响。 含义比整数宽度还要深:这些字符是... ASCII还是ebcdic字符?用英语或SQU产品代码形成单词?要发送到的地址或它来自的回信地址?最低级别的解释(逻辑位;类似于整数,符号或无符号;浮动; BCD;指针)是在指令集层次情境,但是你看,它的所有在一定程度方面:在地址是因为它在信封上打印的位置。它与邮递员的规则有关,而不与CPU有关。上下文是一个很大的连续体,一端是位。


※脚注:DAA指令编码为字节00100111。因此,如果在指令流中读取了该字节,则该字节为前一条指令;如果将其27解释为bcd数字,则该数字为零,并且0x27 = 39为整数(以ASCII 表示的数字9)以及中断表的一部分(INT 13的一半) 2字节地址,用于BIOS服务程序。


1

计算机知道内存位置是一条指令的唯一方法是,称为指令指针的专用寄存器在一个或另一个点指向它们。如果指令指针指向一个存储字,则将其作为指令加载。除此之外,计算机无法知道程序与其他类型数据之间的区别。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.